mirror of
https://github.com/Ed94/gencpp.git
synced 2026-05-05 17:12:53 -07:00
Compare commits
86 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 79a1951861 | |||
| e786d7c3b6 | |||
| e6f30c7e1d | |||
| 6147912783 | |||
| ed9f719a07 | |||
| 500f216da2 | |||
| 12e31276eb | |||
| 65c3fabc52 | |||
| c016e245eb | |||
| 99dbc499fa | |||
| 1c133bfc8d | |||
| 451b71884c | |||
| 4d638a7255 | |||
| ceea184d5a | |||
| 92e0d3ab8b | |||
| 9b059dca47 | |||
| 46562d54e7 | |||
| ec07c70dcf | |||
| 63dd77237a | |||
| cf3908c6f0 | |||
| 266163557f | |||
| 8bb2bc7b1b | |||
| a3407c14d5 | |||
| 47b9c37e94 | |||
| 1c3134218e | |||
| a3e7ec4c72 | |||
| cae1555b11 | |||
| f7709bb64e | |||
| 3a55af9ce4 | |||
| 6081834687 | |||
| a3548a5bd3 | |||
| d686831a7c | |||
| ba1dd1894a | |||
| e00b2f8afb | |||
| 72d088c566 | |||
| c6fba23173 | |||
| d45908fb32 | |||
| a7c9dad9fd | |||
| 63ebd0d094 | |||
| f28ae57f16 | |||
| 2fe708e4be | |||
| 69a9abcd59 | |||
| defe42c15c | |||
| 05e65aa464 | |||
| 8f47f3b30f | |||
| 0bad61fda6 | |||
| ea18792373 | |||
| 16b8a3a164 | |||
| 5b0079fb0c | |||
| 9321a04ebc | |||
| 9b68791e38 | |||
| 2dcc968c39 | |||
| c38b077c37 | |||
| f9b5029e64 | |||
| 2b24511f7d | |||
| 5cd69e1742 | |||
| 007bfa0cb0 | |||
| 37c33ffb3e | |||
| 937235b776 | |||
| f9c21ebc04 | |||
| fec709cc76 | |||
| 80cb3f4eca | |||
| 9e88cb8724 | |||
| f61c1c560d | |||
| 8ef982003a | |||
| 31691b1466 | |||
| ed0c0422ad | |||
| e5acac1d18 | |||
| c7b072266f | |||
| a96d03eaed | |||
| 0b4ccac8f9 | |||
| 31a3609b28 | |||
| fbdb870986 | |||
| 6d04165b96 | |||
| cc245cc263 | |||
| 06deb1e836 | |||
| 5527a27f7b | |||
| a67fdef20a | |||
| 056a5863b8 | |||
| 79eb5f1f76 | |||
| c6cb583518 | |||
| 34eec66f35 | |||
| 4137ebfbd8 | |||
| 5958dd2055 | |||
| 163ad0a511 | |||
| e3c2a577ba |
@@ -31,3 +31,4 @@ project/auxillary/vis_ast/dependencies/temp
|
||||
test/gen/original
|
||||
singleheader/gen/scratch.hpp
|
||||
test/gen/scratch.cpp
|
||||
gen_c_library/gen
|
||||
|
||||
Vendored
+33
-4
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Win32 msvc",
|
||||
"name": "Bootstrap",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**"
|
||||
"${workspaceFolder}/project/**"
|
||||
],
|
||||
"defines": [
|
||||
"_DEBUG",
|
||||
@@ -15,10 +15,39 @@
|
||||
"GEN_INTELLISENSE_DIRECTIVES",
|
||||
"INTELLISENSE_DIRECTIVES"
|
||||
],
|
||||
"cStandard": "c11",
|
||||
"cppStandard": "c++17",
|
||||
"windowsSdkVersion": "10.0.19041.0",
|
||||
"compilerPath": "C:/Program Files/Microsoft Visual Studio/2022/Professional/VC/Tools/MSVC/14.29.30133/bin/HostX64/x64/cl.exe",
|
||||
"intelliSenseMode": "msvc-x64",
|
||||
"compileCommands": "${workspaceFolder}/project/build/compile_commands.json"
|
||||
"compileCommands": "C:\\projects\\gencpp\\.vscode\\tasks.json",
|
||||
"compilerArgs": [
|
||||
"/EHsc-",
|
||||
"/GR-",
|
||||
"/Zc:preprocessor",
|
||||
"/FC"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Win32 msvc c_library",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/gen_c_library/**"
|
||||
],
|
||||
"defines": [
|
||||
"_DEBUG",
|
||||
"UNICODE",
|
||||
"_UNICODE",
|
||||
"GEN_TIME",
|
||||
"GEN_IMPLEMENTATION",
|
||||
// "GEN_DONT_USE_NAMESPACE"
|
||||
"GEN_INTELLISENSE_DIRECTIVES",
|
||||
"INTELLISENSE_DIRECTIVES"
|
||||
],
|
||||
"cppStandard": "c++17",
|
||||
"windowsSdkVersion": "10.0.19041.0",
|
||||
"compilerPath": "C:/Program Files/Microsoft Visual Studio/2022/Professional/VC/Tools/MSVC/14.29.30133/bin/HostX64/x64/cl.exe",
|
||||
"intelliSenseMode": "msvc-x64",
|
||||
"compileCommands": "C:\\projects\\gencpp\\.vscode\\tasks.json"
|
||||
},
|
||||
{
|
||||
"name": "Win32 clang",
|
||||
@@ -38,7 +67,7 @@
|
||||
"windowsSdkVersion": "10.0.19041.0",
|
||||
"compilerPath": "C:/Users/Ed/scoop/apps/llvm/current/bin/clang++.exe",
|
||||
"intelliSenseMode": "windows-clang-x64",
|
||||
"compileCommands": "${workspaceFolder}/project/build/compile_commands.json"
|
||||
"compileCommands": ".vscode/tasks.json"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
|
||||
Vendored
+24
-3
@@ -37,7 +37,26 @@
|
||||
"propidl.h": "c",
|
||||
"android_native_app_glue.h": "c",
|
||||
"raylib.h": "c",
|
||||
"*.m": "cpp"
|
||||
"*.m": "cpp",
|
||||
"atomic": "cpp",
|
||||
"gen.h": "c",
|
||||
"string_ops.hpp": "c",
|
||||
"assert.h": "c",
|
||||
"intrin.h": "c",
|
||||
"bit": "cpp",
|
||||
"cmath": "cpp",
|
||||
"cstddef": "cpp",
|
||||
"cstdint": "cpp",
|
||||
"cstdio": "cpp",
|
||||
"cstdlib": "cpp",
|
||||
"cstring": "cpp",
|
||||
"ctime": "cpp",
|
||||
"cwchar": "cpp",
|
||||
"iosfwd": "cpp",
|
||||
"new": "cpp",
|
||||
"typeinfo": "cpp",
|
||||
"unordered_map": "cpp",
|
||||
"xstddef": "cpp"
|
||||
},
|
||||
"C_Cpp.intelliSenseEngineFallback": "disabled",
|
||||
"mesonbuild.configureOnOpen": true,
|
||||
@@ -48,8 +67,10 @@
|
||||
"C_Cpp.files.exclude": {
|
||||
"**/.vscode": true,
|
||||
"**/.vs": true,
|
||||
"**/sanity.gen.hpp": true
|
||||
"**/sanity.gen.hpp": true,
|
||||
"test/**":true,
|
||||
},
|
||||
"autoHide.autoHidePanel": false,
|
||||
"autoHide.autoHideSideBar": false
|
||||
"autoHide.autoHideSideBar": false,
|
||||
"dimmer.enabled": false
|
||||
}
|
||||
|
||||
Vendored
+144
@@ -0,0 +1,144 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Build Bootstrap",
|
||||
"type": "shell",
|
||||
"command": "C:\\Program Files\\PowerShell\\7\\pwsh.exe",
|
||||
"args": [
|
||||
"-ExecutionPolicy",
|
||||
"Bypass",
|
||||
"-File",
|
||||
"${workspaceFolder}/scripts/build.ci.ps1",
|
||||
"bootstrap",
|
||||
"msvc"
|
||||
],
|
||||
"group": "build",
|
||||
"problemMatcher": {
|
||||
"owner": "cpp",
|
||||
"fileLocation": [
|
||||
"relative",
|
||||
"${workspaceFolder}"
|
||||
],
|
||||
"pattern": {
|
||||
"regexp": "^(.*)\\((\\d+)\\)\\s*:\\s*(warning|error)\\s*(\\w+)\\s*:\\s*(.*)$",
|
||||
"file": 1,
|
||||
"line": 2,
|
||||
"severity": 3,
|
||||
"code": 4,
|
||||
"message": 5
|
||||
}
|
||||
},
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "shared",
|
||||
"clear": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Build C Library",
|
||||
"type": "shell",
|
||||
"command": "C:\\Program Files\\PowerShell\\7\\pwsh.exe",
|
||||
"args": [
|
||||
"-ExecutionPolicy",
|
||||
"Bypass",
|
||||
"-File",
|
||||
"${workspaceFolder}/scripts/build.ci.ps1",
|
||||
"c_library",
|
||||
"msvc"
|
||||
],
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"problemMatcher": {
|
||||
"owner": "cpp",
|
||||
"fileLocation": [
|
||||
"relative",
|
||||
"${workspaceFolder}"
|
||||
],
|
||||
"pattern": {
|
||||
"regexp": "^(.*)\\((\\d+)\\)\\s*:\\s*(warning|error)\\s*(\\w+)\\s*:\\s*(.*)$",
|
||||
"file": 1,
|
||||
"line": 2,
|
||||
"severity": 3,
|
||||
"code": 4,
|
||||
"message": 5
|
||||
}
|
||||
},
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "shared",
|
||||
"clear": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Build Singleheader (MSVC)",
|
||||
"type": "shell",
|
||||
"command": "C:\\Program Files\\PowerShell\\7\\pwsh.exe",
|
||||
"args": [
|
||||
"-ExecutionPolicy",
|
||||
"Bypass",
|
||||
"-File",
|
||||
"${workspaceFolder}/scripts/build.ci.ps1",
|
||||
"singleheader",
|
||||
"msvc",
|
||||
"debug"
|
||||
],
|
||||
"group": "build",
|
||||
"problemMatcher": {
|
||||
"owner": "cpp",
|
||||
"fileLocation": ["relative", "${workspaceFolder}"],
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^(.*)\\((\\d+)\\)\\s*:\\s*(error|warning|info|note)\\s+(\\w{1,2}\\d+)\\s*:\\s*(.*)$",
|
||||
"file": 1,
|
||||
"line": 2,
|
||||
"severity": 3,
|
||||
"code": 4,
|
||||
"message": 5
|
||||
}
|
||||
]
|
||||
},
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "shared",
|
||||
"clear": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Build Unreal (MSVC)",
|
||||
"type": "shell",
|
||||
"command": "C:\\Program Files\\PowerShell\\7\\pwsh.exe",
|
||||
"args": [
|
||||
"-ExecutionPolicy",
|
||||
"Bypass",
|
||||
"-File",
|
||||
"${workspaceFolder}/scripts/build.ci.ps1",
|
||||
"unreal",
|
||||
"msvc",
|
||||
"debug"
|
||||
],
|
||||
"group": "build",
|
||||
"problemMatcher": {
|
||||
"owner": "cpp",
|
||||
"fileLocation": ["relative", "${workspaceFolder}"],
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^(.*)\\((\\d+)\\)\\s*:\\s*(error|warning|info|note)\\s+(\\w{1,2}\\d+)\\s*:\\s*(.*)$",
|
||||
"file": 1,
|
||||
"line": 2,
|
||||
"severity": 3,
|
||||
"code": 4,
|
||||
"message": 5
|
||||
}
|
||||
]
|
||||
},
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "shared",
|
||||
"clear": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
# gencpp
|
||||
|
||||
An attempt at simple staged metaprogramming for c/c++.
|
||||
An attempt at simple staged metaprogramming for C/C++.
|
||||
|
||||
The library API is a composition of code element constructors.
|
||||
These build up a code AST to then serialize with a file builder.
|
||||
The library API is a composition of code element constructors, and a non-standards-compliant single-pass C/C++ parser.
|
||||
These build up a code AST to then serialize with a file builder, or can be traversed for staged-reflection of C/C++ code.
|
||||
|
||||
This code base attempts follow the [handmade philosophy](https://handmade.network/manifesto).
|
||||
Its not meant to be a black box metaprogramming utility, it should be easy to intergrate into a user's project domain.
|
||||
@@ -31,7 +31,7 @@ A metaprogram is built to generate files before the main program is built. We'll
|
||||
|
||||
`gen.cpp` \`s `main()` is defined as `gen_main()` which the user will have to define once for their program. There they will dictate everything that should be generated.
|
||||
|
||||
In order to keep the locality of this code within the same files the following pattern may be used (although this pattern isn't required at all):
|
||||
In order to keep the locality of this code within the same files the following pattern may be used (although this pattern isn't the best to use):
|
||||
|
||||
Within `program.cpp` :
|
||||
|
||||
@@ -54,7 +54,6 @@ u32 gen_main()
|
||||
|
||||
// Regular runtime dependent on the generated code here.
|
||||
#endif
|
||||
|
||||
```
|
||||
|
||||
The design uses a constructive builder API for the code to generate.
|
||||
|
||||
+1
-1
@@ -552,7 +552,7 @@ Serialization:
|
||||
Fields:
|
||||
|
||||
```cpp
|
||||
SpecifierT ArrSpecs[ AST::ArrSpecs_Cap ];
|
||||
SpecifierT ArrSpecs[ AST_ArrSpecs_Cap ];
|
||||
CodeSpecifiers NextSpecs;
|
||||
Code Prev;
|
||||
Code Next;
|
||||
|
||||
+3
-1
@@ -25,6 +25,8 @@ This library was written in a subset of C++ where the following are not used at
|
||||
* Exceptions
|
||||
|
||||
Polymorphic & Member-functions are used as an ergonomic choice, along with a conserative use of operator overloads.
|
||||
The base library itself does not use anything but C-like features to allow for generating a derviative compatiable with C (WIP).
|
||||
|
||||
There are only 4 template definitions in the entire library. (`Array<Type>`, `Hashtable<Type>`, `swap<Type>`, and `AST/Code::cast<Type>`)
|
||||
|
||||
Two generic templated containers are used throughout the library:
|
||||
@@ -99,7 +101,7 @@ union {
|
||||
};
|
||||
StringCached Content; // Attributes, Comment, Execution, Include
|
||||
struct {
|
||||
SpecifierT ArrSpecs[AST::ArrSpecs_Cap]; // Specifiers
|
||||
SpecifierT ArrSpecs[AST_ArrSpecs_Cap]; // Specifiers
|
||||
AST* NextSpecs; // Specifiers
|
||||
};
|
||||
};
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
[*.c]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
|
||||
[*.cpp]
|
||||
indent_style = tab
|
||||
indent_size = 2
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,435 @@
|
||||
#pragma once
|
||||
|
||||
#include "../project/gen.hpp"
|
||||
|
||||
using namespace gen;
|
||||
|
||||
// Used to know what slot the array will be for generic selection
|
||||
global s32 Array_DefinitionCounter = 0;
|
||||
|
||||
CodeBody gen_array_base()
|
||||
{
|
||||
CodeTypedef td_header = parse_typedef( code( typedef struct ArrayHeader ArrayHeader; ));
|
||||
CodeStruct header = parse_struct( code(
|
||||
struct ArrayHeader
|
||||
{
|
||||
AllocatorInfo Allocator;
|
||||
usize Capacity;
|
||||
usize Num;
|
||||
};
|
||||
));
|
||||
|
||||
Code grow_formula = untyped_str( txt( "#define array_grow_formula( value ) ( 2 * value + 8 )\n" ));
|
||||
Code get_header = untyped_str( txt( "#define array_get_header( self ) ( (ArrayHeader*)( self ) - 1)\n" ));
|
||||
Code type_define = untyped_str( txt( "#define Array(Type) Array_##Type\n"));
|
||||
|
||||
Code array_begin = def_define(txt("array_begin(array)"), code( (array) ));
|
||||
Code array_end = def_define(txt("array_end(array)"), code( (array + array_get_header(array)->Num ) ));
|
||||
Code array_next = def_define(txt("array_next(array, entry)"), code( (entry + 1) ));
|
||||
|
||||
return def_global_body( args(
|
||||
fmt_newline,
|
||||
td_header,
|
||||
header,
|
||||
type_define,
|
||||
grow_formula,
|
||||
get_header,
|
||||
array_begin,
|
||||
array_end,
|
||||
array_next,
|
||||
fmt_newline
|
||||
));
|
||||
};
|
||||
|
||||
CodeBody gen_array( StrC type, StrC array_name )
|
||||
{
|
||||
String array_type = String::fmt_buf( GlobalAllocator, "%.*s", array_name.Len, array_name.Ptr );
|
||||
String fn = String::fmt_buf( GlobalAllocator, "%.*s", array_name.Len, array_name.Ptr );
|
||||
// str_to_lower(fn.Data);
|
||||
|
||||
#pragma push_macro( "GEN_ASSERT" )
|
||||
#pragma push_macro( "rcast" )
|
||||
#pragma push_macro( "cast" )
|
||||
#pragma push_macro( "typeof" )
|
||||
#pragma push_macro( "forceinline" )
|
||||
#undef GEN_ASSERT
|
||||
#undef rcast
|
||||
#undef cast
|
||||
#undef typeof
|
||||
#undef forceinline
|
||||
CodeBody result = parse_global_body( token_fmt( "array_type", (StrC)array_type, "fn", (StrC)fn, "type", (StrC)type
|
||||
, stringize(
|
||||
typedef <type>* <array_type>;
|
||||
|
||||
<array_type> <fn>_init ( AllocatorInfo allocator );
|
||||
<array_type> <fn>_init_reserve ( AllocatorInfo allocator, usize capacity );
|
||||
bool <fn>_append_array ( <array_type>* self, <array_type> other );
|
||||
bool <fn>_append ( <array_type>* self, <type> value );
|
||||
bool <fn>_append_items ( <array_type>* self, <type>* items, usize item_num );
|
||||
bool <fn>_append_at ( <array_type>* self, <type> item, usize idx );
|
||||
bool <fn>_append_items_at( <array_type>* self, <type>* items, usize item_num, usize idx );
|
||||
<type>* <fn>_back ( <array_type> self );
|
||||
void <fn>_clear ( <array_type> self );
|
||||
bool <fn>_fill ( <array_type> self, usize begin, usize end, <type> value );
|
||||
void <fn>_free ( <array_type>* self );
|
||||
bool <fn>_grow ( <array_type>* self, usize min_capacity );
|
||||
usize <fn>_num ( <array_type> self );
|
||||
<type> <fn>_pop ( <array_type> self );
|
||||
void <fn>_remove_at ( <array_type> self, usize idx );
|
||||
bool <fn>_reserve ( <array_type>* self, usize new_capacity );
|
||||
bool <fn>_resize ( <array_type>* self, usize num );
|
||||
bool <fn>_set_capacity ( <array_type>* self, usize new_capacity );
|
||||
|
||||
forceinline
|
||||
<array_type> <fn>_init( AllocatorInfo allocator )
|
||||
{
|
||||
size_t initial_size = array_grow_formula(0);
|
||||
return array_init_reserve( <type>, allocator, initial_size );
|
||||
}
|
||||
|
||||
inline
|
||||
<array_type> <fn>_init_reserve( AllocatorInfo allocator, usize capacity )
|
||||
{
|
||||
GEN_ASSERT(capacity > 0);
|
||||
ArrayHeader* header = rcast(ArrayHeader*, alloc(allocator, sizeof(ArrayHeader) + sizeof(<type>) * capacity));
|
||||
|
||||
if (header == nullptr)
|
||||
return nullptr;
|
||||
|
||||
header->Allocator = allocator;
|
||||
header->Capacity = capacity;
|
||||
header->Num = 0;
|
||||
|
||||
return rcast(<type>*, header + 1);
|
||||
}
|
||||
|
||||
forceinline
|
||||
bool <fn>_append_array( <array_type>* self, <array_type> other )
|
||||
{
|
||||
return array_append_items( * self, (<array_type>)other, <fn>_num(other));
|
||||
}
|
||||
|
||||
inline
|
||||
bool <fn>_append( <array_type>* self, <type> value )
|
||||
{
|
||||
GEN_ASSERT( self != nullptr);
|
||||
GEN_ASSERT(* self != nullptr);
|
||||
ArrayHeader* header = array_get_header( * self );
|
||||
|
||||
if ( header->Num == header->Capacity )
|
||||
{
|
||||
if ( ! array_grow( self, header->Capacity))
|
||||
return false;
|
||||
|
||||
header = array_get_header( * self );
|
||||
}
|
||||
|
||||
(* self)[ header->Num ] = value;
|
||||
header->Num++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline
|
||||
bool <fn>_append_items( <array_type>* self, <type>* items, usize item_num )
|
||||
{
|
||||
GEN_ASSERT( self != nullptr);
|
||||
GEN_ASSERT(* self != nullptr);
|
||||
GEN_ASSERT(items != nullptr);
|
||||
GEN_ASSERT(item_num > 0);
|
||||
ArrayHeader* header = array_get_header( * self );
|
||||
|
||||
if ( header->Num + item_num > header->Capacity )
|
||||
{
|
||||
if ( ! array_grow( self, header->Capacity + item_num ))
|
||||
return false;
|
||||
|
||||
header = array_get_header( * self );
|
||||
}
|
||||
|
||||
mem_copy( (* self) + header->Num, items, sizeof(<type>) * item_num );
|
||||
header->Num += item_num;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline
|
||||
bool <fn>_append_at( <array_type>* self, <type> item, usize idx )
|
||||
{
|
||||
GEN_ASSERT( self != nullptr);
|
||||
GEN_ASSERT(* self != nullptr);
|
||||
ArrayHeader* header = array_get_header( * self );
|
||||
|
||||
if ( idx >= header->Num )
|
||||
idx = header->Num - 1;
|
||||
|
||||
if ( idx < 0 )
|
||||
idx = 0;
|
||||
|
||||
if ( header->Capacity < header->Num + 1 )
|
||||
{
|
||||
if ( ! array_grow( self, header->Capacity + 1 ) )
|
||||
return false;
|
||||
|
||||
header = array_get_header( * self );
|
||||
}
|
||||
|
||||
<array_type> target = (* self) + idx;
|
||||
|
||||
mem_move( target + 1, target, (header->Num - idx) * sizeof(<type>) );
|
||||
header->Num++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline
|
||||
bool <fn>_append_items_at( <array_type>* self, <type>* items, usize item_num, usize idx )
|
||||
{
|
||||
GEN_ASSERT( self != nullptr);
|
||||
GEN_ASSERT(* self != nullptr);
|
||||
ArrayHeader* header = array_get_header( * self );
|
||||
|
||||
if ( idx >= header->Num )
|
||||
{
|
||||
return array_append_items( * self, items, item_num );
|
||||
}
|
||||
|
||||
if ( item_num > header->Capacity )
|
||||
{
|
||||
if ( ! array_grow( self, item_num + header->Capacity ) )
|
||||
return false;
|
||||
|
||||
header = array_get_header( * self );
|
||||
}
|
||||
|
||||
<type>* target = (* self) + idx + item_num;
|
||||
<type>* src = (* self) + idx;
|
||||
|
||||
mem_move( target, src, (header->Num - idx) * sizeof(<type>) );
|
||||
mem_copy( src, items, item_num * sizeof(<type>) );
|
||||
header->Num += item_num;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline
|
||||
<type>* <fn>_back( <array_type> self )
|
||||
{
|
||||
GEN_ASSERT(self != nullptr);
|
||||
ArrayHeader* header = array_get_header( self );
|
||||
|
||||
if ( header->Num == 0 )
|
||||
return NULL;
|
||||
|
||||
return self + header->Num - 1;
|
||||
}
|
||||
|
||||
inline
|
||||
void <fn>_clear( <array_type> self )
|
||||
{
|
||||
GEN_ASSERT(self != nullptr);
|
||||
ArrayHeader* header = array_get_header( self );
|
||||
header->Num = 0;
|
||||
}
|
||||
|
||||
inline
|
||||
bool <fn>_fill( <array_type> self, usize begin, usize end, <type> value )
|
||||
{
|
||||
GEN_ASSERT(self != nullptr);
|
||||
GEN_ASSERT(begin <= end);
|
||||
ArrayHeader* header = array_get_header( self );
|
||||
|
||||
if ( begin < 0 || end >= header->Num )
|
||||
return false;
|
||||
|
||||
for ( ssize idx = begin; idx < end; idx ++ )
|
||||
self[ idx ] = value;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline
|
||||
void <fn>_free( <array_type>* self )
|
||||
{
|
||||
GEN_ASSERT( self != nullptr);
|
||||
GEN_ASSERT(* self != nullptr);
|
||||
ArrayHeader* header = array_get_header( * self );
|
||||
allocator_free( header->Allocator, header );
|
||||
self = NULL;
|
||||
}
|
||||
|
||||
inline
|
||||
bool <fn>_grow( <array_type>* self, usize min_capacity )
|
||||
{
|
||||
GEN_ASSERT( self != nullptr);
|
||||
GEN_ASSERT(* self != nullptr);
|
||||
GEN_ASSERT( min_capacity > 0 );
|
||||
ArrayHeader* header = array_get_header( *self );
|
||||
usize new_capacity = array_grow_formula( header->Capacity );
|
||||
|
||||
if ( new_capacity < min_capacity )
|
||||
new_capacity = min_capacity;
|
||||
|
||||
return array_set_capacity( self, new_capacity );
|
||||
}
|
||||
|
||||
forceinline
|
||||
usize <fn>_num( <array_type> self )
|
||||
{
|
||||
GEN_ASSERT( self != nullptr);
|
||||
return array_get_header(self)->Num;
|
||||
}
|
||||
|
||||
inline
|
||||
<type> <fn>_pop( <array_type> self )
|
||||
{
|
||||
GEN_ASSERT( self != nullptr);
|
||||
ArrayHeader* header = array_get_header( self );
|
||||
GEN_ASSERT( header->Num > 0 );
|
||||
|
||||
<type> result = self[ header->Num - 1 ];
|
||||
header->Num--;
|
||||
return result;
|
||||
}
|
||||
|
||||
forceinline
|
||||
void <fn>_remove_at( <array_type> self, usize idx )
|
||||
{
|
||||
GEN_ASSERT( self != nullptr);
|
||||
ArrayHeader* header = array_get_header( self );
|
||||
GEN_ASSERT( idx < header->Num );
|
||||
|
||||
mem_move( self + idx, self + idx + 1, sizeof( <type> ) * ( header->Num - idx - 1 ) );
|
||||
header->Num--;
|
||||
}
|
||||
|
||||
inline
|
||||
bool <fn>_reserve( <array_type>* self, usize new_capacity )
|
||||
{
|
||||
GEN_ASSERT( self != nullptr);
|
||||
GEN_ASSERT(* self != nullptr);
|
||||
GEN_ASSERT(new_capacity > 0);
|
||||
ArrayHeader* header = array_get_header( * self );
|
||||
|
||||
if ( header->Capacity < new_capacity )
|
||||
return array_set_capacity( self, new_capacity );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline
|
||||
bool <fn>_resize( <array_type>* self, usize num )
|
||||
{
|
||||
GEN_ASSERT( self != nullptr);
|
||||
GEN_ASSERT(* self != nullptr);
|
||||
GEN_ASSERT(num > 0);
|
||||
ArrayHeader* header = array_get_header( * self );
|
||||
|
||||
if ( header->Capacity < num )
|
||||
{
|
||||
if ( ! array_grow( self, num ) )
|
||||
return false;
|
||||
|
||||
header = array_get_header( * self );
|
||||
}
|
||||
|
||||
header->Num = num;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline
|
||||
bool <fn>_set_capacity( <array_type>* self, usize new_capacity )
|
||||
{
|
||||
GEN_ASSERT( self != nullptr);
|
||||
GEN_ASSERT(* self != nullptr);
|
||||
GEN_ASSERT( new_capacity > 0 );
|
||||
ArrayHeader* header = array_get_header( * self );
|
||||
|
||||
if ( new_capacity == header->Capacity )
|
||||
return true;
|
||||
|
||||
if ( new_capacity < header->Num )
|
||||
{
|
||||
header->Num = new_capacity;
|
||||
return true;
|
||||
}
|
||||
|
||||
usize size = sizeof( ArrayHeader ) + sizeof( <type> ) * new_capacity;
|
||||
ArrayHeader* new_header = cast( ArrayHeader*, alloc( header->Allocator, size ));
|
||||
|
||||
if ( new_header == NULL )
|
||||
return false;
|
||||
|
||||
mem_move( new_header, header, sizeof( ArrayHeader ) + sizeof( <type> ) * header->Num );
|
||||
new_header->Capacity = new_capacity;
|
||||
|
||||
allocator_free( header->Allocator, & header );
|
||||
|
||||
* self = cast( <type>*, new_header + 1 );
|
||||
return true;
|
||||
}
|
||||
)));
|
||||
#pragma pop_macro( "GEN_ASSERT" )
|
||||
#pragma pop_macro( "rcast" )
|
||||
#pragma pop_macro( "cast" )
|
||||
#pragma pop_macro( "typeof" )
|
||||
#pragma pop_macro( "forceinline" )
|
||||
|
||||
++ Array_DefinitionCounter;
|
||||
StrC slot_str = String::fmt_buf(GlobalAllocator, "%d", Array_DefinitionCounter).to_strc();
|
||||
|
||||
Code generic_interface_slot = untyped_str(token_fmt( "type", type, "array_type", (StrC)array_type, "slot", (StrC)slot_str,
|
||||
R"(#define GENERIC_SLOT_<slot>__array_init <type>, <array_type>_init
|
||||
#define GENERIC_SLOT_<slot>__array_init_reserve <type>, <array_type>_init_reserve
|
||||
#define GENERIC_SLOT_<slot>__array_append <array_type>, <array_type>_append
|
||||
#define GENERIC_SLOT_<slot>__array_append_items <array_type>, <array_type>_append_items
|
||||
#define GENERIC_SLOT_<slot>__array_append_at <array_type>, <array_type>_append_at
|
||||
#define GENERIC_SLOT_<slot>__array_append_items_at <array_type>, <array_type>_append_items_at
|
||||
#define GENERIC_SLOT_<slot>__array_back <array_type>, <array_type>_back
|
||||
#define GENERIC_SLOT_<slot>__array_clear <array_type>, <array_type>_clear
|
||||
#define GENERIC_SLOT_<slot>__array_fill <array_type>, <array_type>_fill
|
||||
#define GENERIC_SLOT_<slot>__array_free <array_type>, <array_type>_free
|
||||
#define GENERIC_SLOT_<slot>__array_grow <array_type>*, <array_type>_grow
|
||||
#define GENERIC_SLOT_<slot>__array_num <array_type>, <array_type>_num
|
||||
#define GENERIC_SLOT_<slot>__array_pop <array_type>, <array_type>_pop
|
||||
#define GENERIC_SLOT_<slot>__array_remove_at <array_type>, <array_type>_remove_at
|
||||
#define GENERIC_SLOT_<slot>__array_reserve <array_type>, <array_type>_reserve
|
||||
#define GENERIC_SLOT_<slot>__array_resize <array_type>, <array_type>_resize
|
||||
#define GENERIC_SLOT_<slot>__array_set_capacity <array_type>*, <array_type>_set_capacity
|
||||
)"
|
||||
));
|
||||
|
||||
return def_global_body( args(
|
||||
def_pragma( string_to_strc( string_fmt_buf( GlobalAllocator, "region %S", array_type ))),
|
||||
fmt_newline,
|
||||
generic_interface_slot,
|
||||
fmt_newline,
|
||||
result,
|
||||
fmt_newline,
|
||||
def_pragma( string_to_strc(string_fmt_buf( GlobalAllocator, "endregion %S", array_type ))),
|
||||
fmt_newline
|
||||
));
|
||||
};
|
||||
|
||||
CodeBody gen_array_generic_selection_interface()
|
||||
{
|
||||
CodeBody interface_defines = def_body(CT_Global_Body);
|
||||
interface_defines.append( gen_generic_selection_function_macro( Array_DefinitionCounter, txt("array_init"), GenericSel_Direct_Type ));
|
||||
interface_defines.append( gen_generic_selection_function_macro( Array_DefinitionCounter, txt("array_init_reserve"), GenericSel_Direct_Type ));
|
||||
interface_defines.append( gen_generic_selection_function_macro( Array_DefinitionCounter, txt("array_append"), GenericSel_By_Ref ));
|
||||
interface_defines.append( gen_generic_selection_function_macro( Array_DefinitionCounter, txt("array_append_at"), GenericSel_By_Ref ));
|
||||
interface_defines.append( gen_generic_selection_function_macro( Array_DefinitionCounter, txt("array_append_items"), GenericSel_By_Ref ));
|
||||
interface_defines.append( gen_generic_selection_function_macro( Array_DefinitionCounter, txt("array_append_items_at"), GenericSel_By_Ref ));
|
||||
interface_defines.append( gen_generic_selection_function_macro( Array_DefinitionCounter, txt("array_back"), GenericSel_Default, GenericSel_One_Arg ));
|
||||
interface_defines.append( gen_generic_selection_function_macro( Array_DefinitionCounter, txt("array_clear"), GenericSel_Default, GenericSel_One_Arg ));
|
||||
interface_defines.append( gen_generic_selection_function_macro( Array_DefinitionCounter, txt("array_fill")) );
|
||||
interface_defines.append( gen_generic_selection_function_macro( Array_DefinitionCounter, txt("array_free"), GenericSel_By_Ref, GenericSel_One_Arg ) );
|
||||
interface_defines.append( gen_generic_selection_function_macro( Array_DefinitionCounter, txt("array_grow")) );
|
||||
interface_defines.append( gen_generic_selection_function_macro( Array_DefinitionCounter, txt("array_num"), GenericSel_Default, GenericSel_One_Arg ));
|
||||
interface_defines.append( gen_generic_selection_function_macro( Array_DefinitionCounter, txt("array_pop"), GenericSel_Default, GenericSel_One_Arg ));
|
||||
interface_defines.append( gen_generic_selection_function_macro( Array_DefinitionCounter, txt("array_remove_at")) );
|
||||
interface_defines.append( gen_generic_selection_function_macro( Array_DefinitionCounter, txt("array_reserve"), GenericSel_By_Ref) );
|
||||
interface_defines.append( gen_generic_selection_function_macro( Array_DefinitionCounter, txt("array_resize"), GenericSel_By_Ref) );
|
||||
interface_defines.append( gen_generic_selection_function_macro( Array_DefinitionCounter, txt("array_set_capacity")) );
|
||||
return interface_defines;
|
||||
}
|
||||
@@ -0,0 +1,434 @@
|
||||
#pragma once
|
||||
|
||||
#include "../project/gen.hpp"
|
||||
#include "containers.array.hpp"
|
||||
|
||||
using namespace gen;
|
||||
|
||||
global s32 HashTable_DefinitionCounter = 0;
|
||||
|
||||
CodeBody gen_hashtable_base()
|
||||
{
|
||||
CodeBody struct_def = parse_global_body( code(
|
||||
typedef struct HT_FindResult_Def HT_FindResult;
|
||||
struct HT_FindResult_Def
|
||||
{
|
||||
ssize HashIndex;
|
||||
ssize PrevIndex;
|
||||
ssize EntryIndex;
|
||||
};
|
||||
));
|
||||
|
||||
Code define_type = untyped_str(txt(
|
||||
R"(#define HashTable(_type) struct _type
|
||||
)"
|
||||
));
|
||||
|
||||
Code define_critical_load_scale = untyped_str(txt("#define HashTable_CriticalLoadScale 0.7f\n"));
|
||||
return def_global_body(args(struct_def, define_type, define_critical_load_scale));
|
||||
}
|
||||
|
||||
CodeBody gen_hashtable( StrC type, StrC hashtable_name )
|
||||
{
|
||||
|
||||
String tbl_type = {(char*) hashtable_name.duplicate(GlobalAllocator).Ptr};
|
||||
String fn = tbl_type.duplicate(GlobalAllocator);
|
||||
// str_to_lower(fn.Data);
|
||||
|
||||
String name_lower = String::make( GlobalAllocator, hashtable_name );
|
||||
// str_to_lower( name_lower.Data );
|
||||
|
||||
String hashtable_entry = String::fmt_buf( GlobalAllocator, "HTE_%.*s", hashtable_name.Len, hashtable_name.Ptr );
|
||||
String entry_array_name = String::fmt_buf( GlobalAllocator, "Arr_HTE_%.*s", hashtable_name.Len, hashtable_name.Ptr );
|
||||
String entry_array_fn_ns = String::fmt_buf( GlobalAllocator, "arr_hte_%.*s", name_lower.length(), name_lower.Data );
|
||||
|
||||
CodeBody hashtable_types = parse_global_body( token_fmt(
|
||||
"type", (StrC) type,
|
||||
"tbl_name", (StrC) hashtable_name,
|
||||
"tbl_type", (StrC) tbl_type,
|
||||
stringize(
|
||||
typedef struct HashTable_<type> <tbl_type>;
|
||||
typedef struct HTE_<tbl_name> HTE_<tbl_name>;
|
||||
struct HTE_<tbl_name> {
|
||||
u64 Key;
|
||||
ssize Next;
|
||||
<type> Value;
|
||||
};
|
||||
|
||||
typedef void (* <tbl_type>_MapProc) ( <tbl_type> self, u64 key, <type> value );
|
||||
typedef void (* <tbl_type>_MapMutProc) ( <tbl_type> self, u64 key, <type>* value );
|
||||
)));
|
||||
|
||||
CodeBody entry_array = gen_array( hashtable_entry, entry_array_name );
|
||||
|
||||
#pragma push_macro( "GEN_ASSERT" )
|
||||
#pragma push_macro( "GEN_ASSERT_NOT_NULL" )
|
||||
#pragma push_macro( "rcast" )
|
||||
#pragma push_macro( "cast" )
|
||||
#pragma push_macro( "typeof" )
|
||||
#pragma push_macro( "forceinline" )
|
||||
#undef GEN_ASSERT
|
||||
#undef GEN_ASSERT_NOT_NULL
|
||||
#undef GEN_ASSERT
|
||||
#undef rcast
|
||||
#undef cast
|
||||
#undef typeof
|
||||
#undef forceinline
|
||||
CodeBody hashtable_def = parse_global_body( token_fmt(
|
||||
"type", (StrC) type,
|
||||
"tbl_name", (StrC) hashtable_name,
|
||||
"tbl_type", (StrC) tbl_type,
|
||||
"fn", (StrC) fn,
|
||||
"entry_type", (StrC) hashtable_entry,
|
||||
"array_entry", (StrC) entry_array_name,
|
||||
"fn_array", (StrC) entry_array_fn_ns,
|
||||
stringize(
|
||||
struct HashTable_<type> {
|
||||
Array_ssize Hashes;
|
||||
<array_entry> Entries;
|
||||
};
|
||||
|
||||
<tbl_type> <fn>_init ( AllocatorInfo allocator );
|
||||
<tbl_type> <fn>_init_reserve( AllocatorInfo allocator, ssize num );
|
||||
void <fn>_clear ( <tbl_type> self );
|
||||
void <fn>_destroy ( <tbl_type>* self );
|
||||
<type>* <fn>_get ( <tbl_type> self, u64 key );
|
||||
void <fn>_map ( <tbl_type> self, <tbl_type>_MapProc map_proc );
|
||||
void <fn>_map_mut ( <tbl_type> self, <tbl_type>_MapMutProc map_proc );
|
||||
void <fn>_grow ( <tbl_type>* self );
|
||||
void <fn>_rehash ( <tbl_type>* self, ssize new_num );
|
||||
void <fn>_rehash_fast ( <tbl_type> self );
|
||||
void <fn>_remove ( <tbl_type> self, u64 key );
|
||||
void <fn>_remove_entry( <tbl_type> self, ssize idx );
|
||||
void <fn>_set ( <tbl_type>* self, u64 key, <type> value );
|
||||
ssize <fn>_slot ( <tbl_type> self, u64 key );
|
||||
|
||||
ssize <fn>__add_entry( <tbl_type>* self, u64 key );
|
||||
HT_FindResult <fn>__find ( <tbl_type> self, u64 key );
|
||||
b32 <fn>__full ( <tbl_type> self );
|
||||
|
||||
<tbl_type> <fn>_init( AllocatorInfo allocator )
|
||||
{
|
||||
<tbl_type> result = hashtable_init_reserve(<type>, allocator, 8);
|
||||
return result;
|
||||
}
|
||||
|
||||
<tbl_type> <fn>_init_reserve( AllocatorInfo allocator, ssize num )
|
||||
{
|
||||
<tbl_type> result = { NULL, NULL };
|
||||
result.Hashes = array_init_reserve(ssize, allocator, num );
|
||||
array_get_header(result.Hashes)->Num = num;
|
||||
array_resize(result.Hashes, num);
|
||||
array_fill(result.Hashes, 0, num, -1);
|
||||
|
||||
result.Entries = array_init_reserve(<entry_type>, allocator, num );
|
||||
return result;
|
||||
}
|
||||
|
||||
void <fn>_clear( <tbl_type> self )
|
||||
{
|
||||
GEN_ASSERT_NOT_NULL(self.Hashes);
|
||||
GEN_ASSERT_NOT_NULL(self.Entries);
|
||||
array_clear( self.Entries );
|
||||
s32 what = array_num(self.Hashes);
|
||||
array_fill( self.Hashes, 0, what, (ssize)-1 );
|
||||
}
|
||||
|
||||
void <fn>_destroy( <tbl_type>* self )
|
||||
{
|
||||
GEN_ASSERT_NOT_NULL(self);
|
||||
GEN_ASSERT_NOT_NULL(self->Hashes);
|
||||
GEN_ASSERT_NOT_NULL(self->Entries);
|
||||
if ( self->Hashes && array_get_header(self->Hashes)->Capacity) {
|
||||
array_free( self->Hashes );
|
||||
array_free( self->Entries );
|
||||
}
|
||||
}
|
||||
|
||||
<type>* <fn>_get( <tbl_type> self, u64 key )
|
||||
{
|
||||
GEN_ASSERT_NOT_NULL(self.Hashes);
|
||||
GEN_ASSERT_NOT_NULL(self.Entries);
|
||||
ssize idx = <fn>__find( self, key ).EntryIndex;
|
||||
if ( idx > 0 )
|
||||
return & self.Entries[idx].Value;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void <fn>_map( <tbl_type> self, <tbl_type>_MapProc map_proc )
|
||||
{
|
||||
GEN_ASSERT_NOT_NULL(self.Hashes);
|
||||
GEN_ASSERT_NOT_NULL(self.Entries);
|
||||
GEN_ASSERT_NOT_NULL( map_proc );
|
||||
|
||||
for ( ssize idx = 0; idx < array_get_header( self.Entries )->Num; idx++ ) {
|
||||
map_proc( self, self.Entries[idx].Key, self.Entries[idx].Value );
|
||||
}
|
||||
}
|
||||
|
||||
void <fn>_map_mut( <tbl_type> self, <tbl_type>_MapMutProc map_proc )
|
||||
{
|
||||
GEN_ASSERT_NOT_NULL(self.Hashes);
|
||||
GEN_ASSERT_NOT_NULL(self.Entries);
|
||||
GEN_ASSERT_NOT_NULL( map_proc );
|
||||
|
||||
for ( ssize idx = 0; idx < array_get_header( self.Entries )->Num; idx++ ) {
|
||||
map_proc( self, self.Entries[idx].Key, & self.Entries[idx].Value );
|
||||
}
|
||||
}
|
||||
|
||||
void <fn>_grow( <tbl_type>* self )
|
||||
{
|
||||
GEN_ASSERT_NOT_NULL(self);
|
||||
GEN_ASSERT_NOT_NULL(self->Hashes);
|
||||
GEN_ASSERT_NOT_NULL(self->Entries);
|
||||
ssize new_num = array_grow_formula( array_get_header( self->Entries )->Num );
|
||||
hashtable_rehash( self, new_num );
|
||||
}
|
||||
|
||||
void <fn>_rehash( <tbl_type>* self, ssize new_num )
|
||||
{
|
||||
GEN_ASSERT_NOT_NULL(self);
|
||||
GEN_ASSERT_NOT_NULL(self->Hashes);
|
||||
GEN_ASSERT_NOT_NULL(self->Entries);
|
||||
GEN_ASSERT( new_num > 0 );
|
||||
ssize idx;
|
||||
ssize last_added_index;
|
||||
|
||||
ArrayHeader* old_hash_header = array_get_header( self->Hashes );
|
||||
ArrayHeader* old_entries_header = array_get_header( self->Entries );
|
||||
|
||||
<tbl_type> new_tbl = hashtable_init_reserve( <type>, old_hash_header->Allocator, old_hash_header->Num );
|
||||
|
||||
ArrayHeader* new_hash_header = array_get_header( new_tbl.Hashes );
|
||||
|
||||
for (ssize idx = 0; idx < cast(ssize, old_hash_header->Num); ++idx)
|
||||
{
|
||||
<entry_type>* entry = & self->Entries[idx];
|
||||
HT_FindResult find_result;
|
||||
|
||||
find_result = <fn>__find( new_tbl, entry->Key);
|
||||
last_added_index = <fn>__add_entry( & new_tbl, entry->Key);
|
||||
|
||||
if (find_result.PrevIndex < 0)
|
||||
new_tbl.Hashes[find_result.HashIndex] = last_added_index;
|
||||
else
|
||||
new_tbl.Entries[find_result.PrevIndex].Next = last_added_index;
|
||||
|
||||
new_tbl.Entries[last_added_index].Next = find_result.EntryIndex;
|
||||
new_tbl.Entries[last_added_index].Value = entry->Value;
|
||||
}
|
||||
|
||||
<fn>_destroy( self );
|
||||
* self = new_tbl;
|
||||
}
|
||||
|
||||
void <fn>_rehash_fast( <tbl_type> self )
|
||||
{
|
||||
GEN_ASSERT_NOT_NULL(self.Hashes);
|
||||
GEN_ASSERT_NOT_NULL(self.Entries);
|
||||
ssize idx;
|
||||
|
||||
for ( idx = 0; idx < array_get_header( self.Entries )->Num; idx++ )
|
||||
self.Entries[ idx ].Next = -1;
|
||||
|
||||
for ( idx = 0; idx < array_get_header( self.Hashes )->Num; idx++ )
|
||||
self.Hashes[ idx ] = -1;
|
||||
|
||||
for ( idx = 0; idx < array_get_header( self.Entries )->Num; idx++ )
|
||||
{
|
||||
<entry_type>* entry;
|
||||
HT_FindResult find_result;
|
||||
|
||||
entry = & self.Entries[ idx ];
|
||||
find_result = <fn>__find( self, entry->Key );
|
||||
|
||||
if ( find_result.PrevIndex < 0 )
|
||||
self.Hashes[ find_result.HashIndex ] = idx;
|
||||
else
|
||||
self.Entries[ find_result.PrevIndex ].Next = idx;
|
||||
}
|
||||
}
|
||||
|
||||
void <fn>_remove( <tbl_type> self, u64 key )
|
||||
{
|
||||
GEN_ASSERT_NOT_NULL(self.Hashes);
|
||||
GEN_ASSERT_NOT_NULL(self.Entries);
|
||||
HT_FindResult find_result = <fn>__find( self, key );
|
||||
|
||||
if ( find_result.EntryIndex >= 0 ) {
|
||||
array_remove_at( self.Entries, find_result.EntryIndex );
|
||||
hashtable_rehash_fast( self );
|
||||
}
|
||||
}
|
||||
|
||||
void <fn>_remove_entry( <tbl_type> self, ssize idx )
|
||||
{
|
||||
GEN_ASSERT_NOT_NULL(self.Hashes);
|
||||
GEN_ASSERT_NOT_NULL(self.Entries);
|
||||
array_remove_at( self.Entries, idx );
|
||||
}
|
||||
|
||||
void <fn>_set( <tbl_type>* self, u64 key, <type> value )
|
||||
{
|
||||
GEN_ASSERT_NOT_NULL(self);
|
||||
GEN_ASSERT_NOT_NULL(self->Hashes);
|
||||
GEN_ASSERT_NOT_NULL(self->Entries);
|
||||
ssize idx;
|
||||
HT_FindResult find_result;
|
||||
|
||||
if ( array_get_header( self->Hashes )->Num == 0 )
|
||||
hashtable_grow( self );
|
||||
|
||||
find_result = <fn>__find( * self, key );
|
||||
|
||||
if ( find_result.EntryIndex >= 0 ) {
|
||||
idx = find_result.EntryIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
idx = <fn>__add_entry( self, key );
|
||||
|
||||
if ( find_result.PrevIndex >= 0 ) {
|
||||
self->Entries[ find_result.PrevIndex ].Next = idx;
|
||||
}
|
||||
else {
|
||||
self->Hashes[ find_result.HashIndex ] = idx;
|
||||
}
|
||||
}
|
||||
|
||||
self->Entries[ idx ].Value = value;
|
||||
|
||||
if ( <fn>__full( * self ) )
|
||||
hashtable_grow( self );
|
||||
}
|
||||
|
||||
ssize <fn>_slot( <tbl_type> self, u64 key )
|
||||
{
|
||||
GEN_ASSERT_NOT_NULL(self.Hashes);
|
||||
GEN_ASSERT_NOT_NULL(self.Entries);
|
||||
for ( ssize idx = 0; idx < array_get_header( self.Hashes )->Num; ++idx )
|
||||
if ( self.Hashes[ idx ] == key )
|
||||
return idx;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize <fn>__add_entry( <tbl_type>* self, u64 key )
|
||||
{
|
||||
GEN_ASSERT_NOT_NULL(self);
|
||||
GEN_ASSERT_NOT_NULL(self->Hashes);
|
||||
GEN_ASSERT_NOT_NULL(self->Entries);
|
||||
ssize idx;
|
||||
<entry_type> entry = { key, -1 };
|
||||
|
||||
idx = array_get_header( self->Entries )->Num;
|
||||
array_append( self->Entries, entry );
|
||||
return idx;
|
||||
}
|
||||
|
||||
HT_FindResult <fn>__find( <tbl_type> self, u64 key )
|
||||
{
|
||||
GEN_ASSERT_NOT_NULL(self.Hashes);
|
||||
GEN_ASSERT_NOT_NULL(self.Entries);
|
||||
HT_FindResult result = { -1, -1, -1 };
|
||||
|
||||
ArrayHeader* hash_header = array_get_header( self.Hashes );
|
||||
if ( hash_header->Num > 0 )
|
||||
{
|
||||
result.HashIndex = key % hash_header->Num;
|
||||
result.EntryIndex = self.Hashes[ result.HashIndex ];
|
||||
|
||||
while ( result.EntryIndex >= 0 )
|
||||
{
|
||||
if ( self.Entries[ result.EntryIndex ].Key == key )
|
||||
break;
|
||||
|
||||
result.PrevIndex = result.EntryIndex;
|
||||
result.EntryIndex = self.Entries[ result.EntryIndex ].Next;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
b32 <fn>__full( <tbl_type> self )
|
||||
{
|
||||
GEN_ASSERT_NOT_NULL(self.Hashes);
|
||||
GEN_ASSERT_NOT_NULL(self.Entries);
|
||||
ArrayHeader* hash_header = array_get_header( self.Hashes );
|
||||
ArrayHeader* entries_header = array_get_header( self.Entries );
|
||||
|
||||
usize critical_load = cast(usize, HashTable_CriticalLoadScale * cast(f32, hash_header->Num));
|
||||
b32 result = entries_header->Num > critical_load;
|
||||
return result;
|
||||
}
|
||||
)));
|
||||
#pragma pop_macro( "GEN_ASSERT" )
|
||||
#pragma pop_macro( "GEN_ASSERT_NOT_NULL" )
|
||||
#pragma pop_macro( "rcast" )
|
||||
#pragma pop_macro( "cast" )
|
||||
#pragma pop_macro( "typeof" )
|
||||
#pragma pop_macro( "forceinline" )
|
||||
|
||||
++ HashTable_DefinitionCounter;
|
||||
StrC slot_str = String::fmt_buf(GlobalAllocator, "%d", HashTable_DefinitionCounter).to_strc();
|
||||
|
||||
Code generic_interface_slot = untyped_str(token_fmt( "type", type, "tbl_type", (StrC)tbl_type, "slot", (StrC)slot_str,
|
||||
R"(#define GENERIC_SLOT_<slot>__hashtable_init <type>, <tbl_type>_init
|
||||
#define GENERIC_SLOT_<slot>__hashtable_init_reserve <type>, <tbl_type>_init_reserve
|
||||
#define GENERIC_SLOT_<slot>__hashtable_clear <tbl_type>, <tbl_type>_clear
|
||||
#define GENERIC_SLOT_<slot>__hashtable_destroy <tbl_type>, <tbl_type>_destroy
|
||||
#define GENERIC_SLOT_<slot>__hashtable_get <tbl_type>, <tbl_type>_get
|
||||
#define GENERIC_SLOT_<slot>__hashtable_map <tbl_type>, <tbl_type>_map
|
||||
#define GENERIC_SLOT_<slot>__hashtable_map_mut <tbl_type>, <tbl_type>_map_mut
|
||||
#define GENERIC_SLOT_<slot>__hashtable_grow <tbl_type>*, <tbl_type>_grow
|
||||
#define GENERIC_SLOT_<slot>__hashtable_rehash <tbl_type>*, <tbl_type>_rehash
|
||||
#define GENERIC_SLOT_<slot>__hashtable_rehash_fast <tbl_type>, <tbl_type>_rehash_fast
|
||||
#define GENERIC_SLOT_<slot>__hashtable_remove_entry <tbl_type>, <tbl_type>_remove_entry
|
||||
#define GENERIC_SLOT_<slot>__hashtable_set <tbl_type>, <tbl_type>_set
|
||||
#define GENERIC_SLOT_<slot>__hashtable_slot <tbl_type>, <tbl_type>_slot
|
||||
|
||||
#define GENERIC_SLOT_<slot>__hashtable__add_entry <tbl_type>*, <tbl_type>__add_entry
|
||||
#define GENERIC_SLOT_<slot>__hashtable__find <tbl_type>, <tbl_type>__find
|
||||
#define GENERIC_SLOT_<slot>__hashtable__full <tbl_type>, <tbl_type>__full
|
||||
)"
|
||||
));
|
||||
|
||||
char const* cmt_str = str_fmt_buf( "Name: %.*s Type: %.*s"
|
||||
, tbl_type.length(), tbl_type.Data
|
||||
, type.Len, type.Ptr );
|
||||
|
||||
return def_global_body(args(
|
||||
def_pragma( string_to_strc( string_fmt_buf( GlobalAllocator, "region %S", tbl_type ))),
|
||||
fmt_newline,
|
||||
generic_interface_slot,
|
||||
fmt_newline,
|
||||
hashtable_types,
|
||||
fmt_newline,
|
||||
entry_array,
|
||||
hashtable_def,
|
||||
fmt_newline,
|
||||
def_pragma( string_to_strc( string_fmt_buf( GlobalAllocator, "endregion %S", tbl_type ))),
|
||||
fmt_newline
|
||||
));
|
||||
}
|
||||
|
||||
CodeBody gen_hashtable_generic_selection_interface()
|
||||
{
|
||||
CodeBody interface_defines = def_body(CT_Global_Body);
|
||||
interface_defines.append( gen_generic_selection_function_macro( HashTable_DefinitionCounter, txt("hashtable_init"), GenericSel_Direct_Type ));
|
||||
interface_defines.append( gen_generic_selection_function_macro( HashTable_DefinitionCounter, txt("hashtable_init_reserve"), GenericSel_Direct_Type ));
|
||||
interface_defines.append( gen_generic_selection_function_macro( HashTable_DefinitionCounter, txt("hashtable_clear"), GenericSel_Default, GenericSel_One_Arg ));
|
||||
interface_defines.append( gen_generic_selection_function_macro( HashTable_DefinitionCounter, txt("hashtable_destroy"), GenericSel_By_Ref, GenericSel_One_Arg ) );
|
||||
interface_defines.append( gen_generic_selection_function_macro( HashTable_DefinitionCounter, txt("hashtable_get") ));
|
||||
interface_defines.append( gen_generic_selection_function_macro( HashTable_DefinitionCounter, txt("hashtable_grow"), GenericSel_Default, GenericSel_One_Arg ));
|
||||
interface_defines.append( gen_generic_selection_function_macro( HashTable_DefinitionCounter, txt("hashtable_rehash") ));
|
||||
interface_defines.append( gen_generic_selection_function_macro( HashTable_DefinitionCounter, txt("hashtable_rehash_fast"), GenericSel_Default, GenericSel_One_Arg ));
|
||||
interface_defines.append( gen_generic_selection_function_macro( HashTable_DefinitionCounter, txt("hashtable_remove") ));
|
||||
interface_defines.append( gen_generic_selection_function_macro( HashTable_DefinitionCounter, txt("hashtable_remove_entry") ));
|
||||
interface_defines.append( gen_generic_selection_function_macro( HashTable_DefinitionCounter, txt("hashtable_set"), GenericSel_By_Ref ));
|
||||
interface_defines.append( gen_generic_selection_function_macro( HashTable_DefinitionCounter, txt("hashtable_slot") ));
|
||||
return interface_defines;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
gencpp: An attempt at "simple" staged metaprogramming for c/c++.
|
||||
|
||||
See Readme.md for more information from the project repository.
|
||||
|
||||
Public Address:
|
||||
https://github.com/Ed94/gencpp ---------------------------------------------------------------.
|
||||
| _____ _____ _ _ ___ __ __ |
|
||||
| / ____) / ____} | | | / ,__} / | / | |
|
||||
| | / ___ ___ _ __ ___ _ __ _ __ | {___ | l_ __ _ __ _, ___ __| | | | '-l | '-l | |
|
||||
| | |{_ \/ __\ '_ \ / __} '_ l| '_ l \___ \| __/ _` |/ _` |/ __\/ _` | | | | | | | |
|
||||
| | l__j | ___/ | | | {__; ;_l } ;_l } ____} | l| (_} | {_| | ___j {_; | | l___ _J l_ _J l_ |
|
||||
| \_____|\___}_l |_|\___} .__/| .__/ {_____/ \__\__/_l\__. |\___/\__,_l \____}{_____}{_____} |
|
||||
| | | | | __} | |
|
||||
| l_l l_l {___/ |
|
||||
! ----------------------------------------------------------------------- VERSION: v0.20-Alpha |
|
||||
! ============================================================================================= |
|
||||
! WARNING: THIS IS AN ALPHA VERSION OF THE LIBRARY, USE AT YOUR OWN DISCRETION |
|
||||
! NEVER DO CODE GENERATION WITHOUT AT LEAST HAVING CONTENT IN A CODEBASE UNDER VERSION CONTROL |
|
||||
! ============================================================================================= /
|
||||
*/
|
||||
#if ! defined(GEN_DONT_ENFORCE_GEN_TIME_GUARD) && ! defined(GEN_TIME)
|
||||
# error Gen.hpp : GEN_TIME not defined
|
||||
#endif
|
||||
@@ -0,0 +1,130 @@
|
||||
#pragma once
|
||||
#include "../project/gen.hpp"
|
||||
|
||||
using namespace gen;
|
||||
|
||||
CodeBody gen_fixed_arenas()
|
||||
{
|
||||
CodeBody result = def_body(CT_Global_Body);
|
||||
result.append(def_pragma(txt("region FixedArena")));
|
||||
|
||||
char const* template_struct = stringize(
|
||||
struct FixedArena_<Name>
|
||||
{
|
||||
char memory[<Size>];
|
||||
Arena arena;
|
||||
};
|
||||
typedef struct FixedArena_<Name> FixedArena_<Name>;
|
||||
);
|
||||
|
||||
char const* template_interface = stringize(
|
||||
inline
|
||||
void fixed_arena_init_<Name>(FixedArena_<Name>* result)
|
||||
{
|
||||
result->arena = arena_init_from_memory(& result->memory[0], <Size>);
|
||||
}
|
||||
|
||||
inline
|
||||
ssize fixed_arena_size_remaining_<Name>(FixedArena_<Name>* fixed_arena, ssize alignment)
|
||||
{
|
||||
return arena_size_remaining( & fixed_arena->arena, alignment);
|
||||
}
|
||||
);
|
||||
|
||||
CodeBody arena_struct_1kb = parse_global_body( token_fmt_impl( 3, "Name", txt("1KB"), "Size", txt("kilobytes(1)"), template_struct ));
|
||||
CodeBody arena_struct_4kb = parse_global_body( token_fmt_impl( 3, "Name", txt("4KB"), "Size", txt("kilobytes(4)"), template_struct ));
|
||||
CodeBody arena_struct_8kb = parse_global_body( token_fmt_impl( 3, "Name", txt("8KB"), "Size", txt("kilobytes(8)"), template_struct ));
|
||||
CodeBody arena_struct_16kb = parse_global_body( token_fmt_impl( 3, "Name", txt("16KB"), "Size", txt("kilobytes(16)"), template_struct ));
|
||||
CodeBody arena_struct_32kb = parse_global_body( token_fmt_impl( 3, "Name", txt("32KB"), "Size", txt("kilobytes(32)"), template_struct ));
|
||||
CodeBody arena_struct_64kb = parse_global_body( token_fmt_impl( 3, "Name", txt("64KB"), "Size", txt("kilobytes(64)"), template_struct ));
|
||||
CodeBody arena_struct_128kb = parse_global_body( token_fmt_impl( 3, "Name", txt("128KB"), "Size", txt("kilobytes(128)"), template_struct ));
|
||||
CodeBody arena_struct_256kb = parse_global_body( token_fmt_impl( 3, "Name", txt("256KB"), "Size", txt("kilobytes(256)"), template_struct ));
|
||||
CodeBody arena_struct_512kb = parse_global_body( token_fmt_impl( 3, "Name", txt("512KB"), "Size", txt("kilobytes(512)"), template_struct ));
|
||||
CodeBody arena_struct_1mb = parse_global_body( token_fmt_impl( 3, "Name", txt("1MB"), "Size", txt("megabytes(1)"), template_struct ));
|
||||
CodeBody arena_struct_2mb = parse_global_body( token_fmt_impl( 3, "Name", txt("2MB"), "Size", txt("megabytes(2)"), template_struct ));
|
||||
CodeBody arena_struct_4mb = parse_global_body( token_fmt_impl( 3, "Name", txt("4MB"), "Size", txt("megabytes(4)"), template_struct ));
|
||||
|
||||
|
||||
CodeBody arena_interface_1kb = parse_global_body( token_fmt_impl( 3, "Name", txt("1KB"), "Size", txt("kilobytes(1)"), template_interface ));
|
||||
CodeBody arena_interface_4kb = parse_global_body( token_fmt_impl( 3, "Name", txt("4KB"), "Size", txt("kilobytes(4)"), template_interface ));
|
||||
CodeBody arena_interface_8kb = parse_global_body( token_fmt_impl( 3, "Name", txt("8KB"), "Size", txt("kilobytes(8)"), template_interface ));
|
||||
CodeBody arena_interface_16kb = parse_global_body( token_fmt_impl( 3, "Name", txt("16KB"), "Size", txt("kilobytes(16)"), template_interface ));
|
||||
CodeBody arena_interface_32kb = parse_global_body( token_fmt_impl( 3, "Name", txt("32KB"), "Size", txt("kilobytes(32)"), template_interface ));
|
||||
CodeBody arena_interface_64kb = parse_global_body( token_fmt_impl( 3, "Name", txt("64KB"), "Size", txt("kilobytes(64)"), template_interface ));
|
||||
CodeBody arena_interface_128kb = parse_global_body( token_fmt_impl( 3, "Name", txt("128KB"), "Size", txt("kilobytes(128)"), template_interface ));
|
||||
CodeBody arena_interface_256kb = parse_global_body( token_fmt_impl( 3, "Name", txt("256KB"), "Size", txt("kilobytes(256)"), template_interface ));
|
||||
CodeBody arena_interface_512kb = parse_global_body( token_fmt_impl( 3, "Name", txt("512KB"), "Size", txt("kilobytes(512)"), template_interface ));
|
||||
CodeBody arena_interface_1mb = parse_global_body( token_fmt_impl( 3, "Name", txt("1MB"), "Size", txt("megabytes(1)"), template_interface ));
|
||||
CodeBody arena_interface_2mb = parse_global_body( token_fmt_impl( 3, "Name", txt("2MB"), "Size", txt("megabytes(2)"), template_interface ));
|
||||
CodeBody arena_interface_4mb = parse_global_body( token_fmt_impl( 3, "Name", txt("4MB"), "Size", txt("megabytes(4)"), template_interface ));
|
||||
|
||||
result.append(arena_struct_1kb);
|
||||
result.append(arena_struct_4kb);
|
||||
result.append(arena_struct_8kb);
|
||||
result.append(arena_struct_16kb);
|
||||
result.append(arena_struct_32kb);
|
||||
result.append(arena_struct_64kb);
|
||||
result.append(arena_struct_128kb);
|
||||
result.append(arena_struct_256kb);
|
||||
result.append(arena_struct_512kb);
|
||||
result.append(arena_struct_1mb);
|
||||
result.append(arena_struct_2mb);
|
||||
result.append(arena_struct_4mb);
|
||||
|
||||
result.append(arena_interface_1kb);
|
||||
result.append(arena_interface_4kb);
|
||||
result.append(arena_interface_8kb);
|
||||
result.append(arena_interface_16kb);
|
||||
result.append(arena_interface_32kb);
|
||||
result.append(arena_interface_64kb);
|
||||
result.append(arena_interface_128kb);
|
||||
result.append(arena_interface_256kb);
|
||||
result.append(arena_interface_512kb);
|
||||
result.append(arena_interface_1mb);
|
||||
result.append(arena_interface_2mb);
|
||||
result.append(arena_interface_4mb);
|
||||
|
||||
CodeDefine def = def_define(txt("fixed_arena_allocator_info(fixed_arena)"), code({ arena_allocator_proc, & fixed_arena.arena }) );
|
||||
result.append(def);
|
||||
result.append(fmt_newline);
|
||||
|
||||
result.append(parse_global_body(txt(R"(
|
||||
#define fixed_arena_init(expr) _Generic((expr), \
|
||||
FixedArena_1KB* : fixed_arena_init_1KB, \
|
||||
FixedArena_4KB* : fixed_arena_init_4KB, \
|
||||
FixedArena_8KB* : fixed_arena_init_8KB, \
|
||||
FixedArena_16KB* : fixed_arena_init_16KB, \
|
||||
FixedArena_32KB* : fixed_arena_init_32KB, \
|
||||
FixedArena_64KB* : fixed_arena_init_64KB, \
|
||||
FixedArena_128KB* : fixed_arena_init_128KB, \
|
||||
FixedArena_256KB* : fixed_arena_init_256KB, \
|
||||
FixedArena_512KB* : fixed_arena_init_512KB, \
|
||||
FixedArena_1MB* : fixed_arena_init_1MB, \
|
||||
FixedArena_2MB* : fixed_arena_init_2MB, \
|
||||
FixedArena_4MB* : fixed_arena_init_4MB, \
|
||||
default : gen_generic_selection_fail \
|
||||
) GEN_RESOLVED_FUNCTION_CALL(& expr)
|
||||
|
||||
#define fixed_arena_size_remaining(expr, alignment) _Generic((expr), \
|
||||
FixedArena_1KB* : fixed_arena_size_remaining_1KB, \
|
||||
FixedArena_4KB* : fixed_arena_size_remaining_4KB, \
|
||||
FixedArena_8KB* : fixed_arena_size_remaining_8KB, \
|
||||
FixedArena_16KB* : fixed_arena_size_remaining_16KB, \
|
||||
FixedArena_32KB* : fixed_arena_size_remaining_32KB, \
|
||||
FixedArena_64KB* : fixed_arena_size_remaining_64KB, \
|
||||
FixedArena_128KB* : fixed_arena_size_remaining_128KB, \
|
||||
FixedArena_256KB* : fixed_arena_size_remaining_256KB, \
|
||||
FixedArena_512KB* : fixed_arena_size_remaining_512KB, \
|
||||
FixedArena_1MB* : fixed_arena_size_remaining_1MB, \
|
||||
FixedArena_2MB* : fixed_arena_size_remaining_2MB, \
|
||||
FixedArena_4MB* : fixed_arena_size_remaining_4MB, \
|
||||
default : gen_generic_selection_fail \
|
||||
) GEN_RESOLVED_FUNCTION_CALL(& expr, alignment)
|
||||
)"
|
||||
)));
|
||||
|
||||
result.append(fmt_newline);
|
||||
result.append(def_pragma(txt("endregion FixedArena")));
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,255 @@
|
||||
#pragma once
|
||||
#include "../project/gen.hpp"
|
||||
|
||||
using namespace gen;
|
||||
|
||||
void convert_cpp_enum_to_c( CodeEnum to_convert, CodeBody to_append )
|
||||
{
|
||||
#pragma push_macro("enum_underlying")
|
||||
#undef enum_underlying
|
||||
if (to_convert->UnderlyingType)
|
||||
{
|
||||
to_convert->UnderlyingTypeMacro = untyped_str(token_fmt("type", to_convert->UnderlyingType->Name, stringize(enum_underlying(<type>))));
|
||||
to_convert->UnderlyingType = CodeTypename{nullptr};
|
||||
}
|
||||
CodeTypedef tdef = parse_typedef(token_fmt("name", to_convert->Name, stringize( typedef enum <name> <name>; )));
|
||||
to_append.append(to_convert);
|
||||
to_append.append(tdef);
|
||||
#pragma pop_macro("enum_underlying")
|
||||
}
|
||||
|
||||
b32 ignore_preprocess_cond_block( StrC cond_sig, Code& entry_iter, CodeBody& parsed_body, CodeBody& body )
|
||||
{
|
||||
b32 found = false;
|
||||
CodePreprocessCond cond = cast(CodePreprocessCond, entry_iter);
|
||||
if ( cond->Content.is_equal(cond_sig) )
|
||||
{
|
||||
//log_fmt("Preprocess cond found: %SC\n", cond->Content);
|
||||
found = true;
|
||||
|
||||
s32 depth = 1;
|
||||
++ entry_iter;
|
||||
for(b32 continue_for = true; continue_for && entry_iter != parsed_body.end(); ) switch
|
||||
(entry_iter->Type) {
|
||||
case CT_Preprocess_If:
|
||||
case CT_Preprocess_IfDef:
|
||||
case CT_Preprocess_IfNotDef:
|
||||
++ depth;
|
||||
++ entry_iter;
|
||||
break;
|
||||
|
||||
case CT_Preprocess_Else:
|
||||
++ entry_iter;
|
||||
for(; continue_for && entry_iter != parsed_body.end(); ++ entry_iter)
|
||||
{
|
||||
if (entry_iter->Type == CT_Preprocess_EndIf)
|
||||
{
|
||||
continue_for = false;
|
||||
break;
|
||||
}
|
||||
body.append(entry_iter);
|
||||
}
|
||||
break;
|
||||
|
||||
case CT_Preprocess_EndIf:
|
||||
{
|
||||
depth --;
|
||||
if (depth == 0) {
|
||||
continue_for = false;
|
||||
break;
|
||||
}
|
||||
++ entry_iter;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
++ entry_iter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
constexpr bool GenericSel_One_Arg = true;
|
||||
enum GenericSelectionOpts : u32 { GenericSel_Default, GenericSel_By_Ref, GenericSel_Direct_Type };
|
||||
Code gen_generic_selection_function_macro( s32 num_slots, StrC macro_name, GenericSelectionOpts opts = GenericSel_Default, bool one_arg = false )
|
||||
{
|
||||
/* Implements:
|
||||
#define GEN_FUNCTION_GENERIC_EXAMPLE( selector_arg, ... ) _Generic( \
|
||||
(selector_arg), \
|
||||
GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( FunctionID__ARGS_SIG_1 ) \
|
||||
GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( FunctionID__ARGS_SIG_2 ) \
|
||||
... \
|
||||
GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT_LAST(FunctionID__ARGS_SIG_N ) \
|
||||
) GEN_RESOLVED_FUNCTION_CALL( selector_arg )
|
||||
*/
|
||||
local_persist
|
||||
String define_builder = String::make_reserve(GlobalAllocator, kilobytes(64));
|
||||
define_builder.clear();
|
||||
|
||||
StrC macro_begin;
|
||||
if (opts == GenericSel_Direct_Type) {
|
||||
macro_begin = token_fmt( "macro_name", (StrC)macro_name,
|
||||
R"(#define <macro_name>(selector_arg, ...) _Generic( (*(selector_arg*)NULL ), \
|
||||
)"
|
||||
);
|
||||
}
|
||||
else {
|
||||
macro_begin = token_fmt( "macro_name", (StrC)macro_name,
|
||||
R"(#define <macro_name>(selector_arg, ...) _Generic( (selector_arg), \
|
||||
)"
|
||||
);
|
||||
}
|
||||
define_builder.append(macro_begin);
|
||||
|
||||
for ( s32 slot = 1; slot <= num_slots; ++ slot )
|
||||
{
|
||||
StrC slot_str = String::fmt_buf(GlobalAllocator, "%d", slot).to_strc();
|
||||
if (slot == num_slots && false)
|
||||
{
|
||||
define_builder.append( token_fmt( "macro_name", macro_name, "slot", slot_str,
|
||||
R"( GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT_LAST( GENERIC_SLOT_<slot>__<macro_name> ) \
|
||||
)"
|
||||
));
|
||||
// if ( one_arg )
|
||||
// define_builder.append(token_fmt( "macro_name", macro_name, stringize(
|
||||
// default: static_assert(false, "<macro_name>: Failed to select correct function signature (Did you pass the type?)")
|
||||
// )));
|
||||
// else
|
||||
// define_builder.append(token_fmt( "macro_name", macro_name, stringize(
|
||||
// default: static_assert(false, "<macro_name>: Failed to select correct function signature")
|
||||
// )));
|
||||
continue;
|
||||
}
|
||||
|
||||
define_builder.append( token_fmt( "macro_name", macro_name, "slot", slot_str,
|
||||
R"( GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( GENERIC_SLOT_<slot>__<macro_name> ) \
|
||||
)"
|
||||
));
|
||||
}
|
||||
|
||||
define_builder.append( txt("default: gen_generic_selection_fail") );
|
||||
|
||||
if ( ! one_arg )
|
||||
{
|
||||
if (opts == GenericSel_By_Ref)
|
||||
define_builder.append(txt("\t)\tGEN_RESOLVED_FUNCTION_CALL( & selector_arg, __VA_ARGS__ )"));
|
||||
else if (opts == GenericSel_Direct_Type)
|
||||
define_builder.append(txt("\t)\tGEN_RESOLVED_FUNCTION_CALL( __VA_ARGS__ )"));
|
||||
else
|
||||
define_builder.append(txt("\t)\tGEN_RESOLVED_FUNCTION_CALL( selector_arg, __VA_ARGS__ )"));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (opts == GenericSel_By_Ref)
|
||||
define_builder.append(txt("\t)\tGEN_RESOLVED_FUNCTION_CALL( & selector_arg )"));
|
||||
else if (opts == GenericSel_Direct_Type)
|
||||
define_builder.append(txt("\t)\tGEN_RESOLVED_FUNCTION_CALL()"));
|
||||
else
|
||||
define_builder.append(txt("\t)\tGEN_RESOLVED_FUNCTION_CALL( selector_arg )"));
|
||||
}
|
||||
|
||||
// Add gap for next definition
|
||||
define_builder.append(txt("\n\n"));
|
||||
|
||||
Code macro = untyped_str(define_builder.to_strc());
|
||||
return macro;
|
||||
}
|
||||
|
||||
CodeFn rename_function_to_unique_symbol(CodeFn fn, StrC optional_prefix = txt(""))
|
||||
{
|
||||
// Get basic components for the name
|
||||
StrC old_name = fn->Name;
|
||||
String new_name;
|
||||
|
||||
// Add prefix if provided
|
||||
if (optional_prefix.Len)
|
||||
new_name = string_fmt_buf(GlobalAllocator, "%SC_%SC_", optional_prefix, old_name);
|
||||
else
|
||||
new_name = string_fmt_buf(GlobalAllocator, "%SC_", old_name);
|
||||
|
||||
// Add return type to the signature
|
||||
if (fn->ReturnType)
|
||||
new_name.append_fmt("_%SC", fn->ReturnType->Name);
|
||||
|
||||
// Add parameter types to create a unique signature
|
||||
bool first_param = true;
|
||||
for (CodeParam param = fn->Params; param.ast; param = param->Next)
|
||||
{
|
||||
if (param->ValueType)
|
||||
{
|
||||
// Add separator for readability
|
||||
if (first_param)
|
||||
{
|
||||
new_name.append("_P_");
|
||||
first_param = false;
|
||||
}
|
||||
else
|
||||
new_name.append("_");
|
||||
|
||||
// Add parameter type, handle any specifiers
|
||||
if (param->ValueType->Specs && param->ValueType->Specs->NumEntries > 0)
|
||||
{
|
||||
// Add specifiers (const, volatile, etc)
|
||||
for (Specifier spec : param->ValueType->Specs)
|
||||
{
|
||||
if (spec == Spec_Ptr) {
|
||||
new_name.append("ptr_");
|
||||
continue;
|
||||
}
|
||||
|
||||
new_name.append_fmt("%SC_", spec_to_str(spec));
|
||||
}
|
||||
}
|
||||
|
||||
new_name.append_fmt("%SC", param->ValueType->Name);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle function specifiers if present
|
||||
if (fn->Specs && fn->Specs->NumEntries > 0)
|
||||
{
|
||||
new_name.append("_S_");
|
||||
for (Specifier* spec = begin(fn->Specs);
|
||||
spec != end(fn->Specs);
|
||||
++spec)
|
||||
{
|
||||
new_name.append_fmt("%SC_", spec_to_str(*spec));
|
||||
}
|
||||
}
|
||||
|
||||
fn->Name = new_name;
|
||||
return fn;
|
||||
}
|
||||
|
||||
using SwapContentProc = CodeBody(void);
|
||||
bool swap_pragma_region_implementation( StrC region_name, SwapContentProc* swap_content, Code& entry_iter, CodeBody& body )
|
||||
{
|
||||
bool found = false;
|
||||
CodePragma possible_region = cast(CodePragma, entry_iter);
|
||||
|
||||
String region_sig = string_fmt_buf(GlobalAllocator, "region %s", region_name.Ptr);
|
||||
String endregion_sig = string_fmt_buf(GlobalAllocator, "endregion %s", region_name.Ptr);
|
||||
if ( possible_region->Content.contains(region_sig))
|
||||
{
|
||||
found = true;
|
||||
// body.append(possible_region);
|
||||
body.append(swap_content());
|
||||
|
||||
++ entry_iter;
|
||||
for(b32 continue_for = true; continue_for; ++entry_iter) switch
|
||||
(entry_iter->Type) {
|
||||
case CT_Preprocess_Pragma:
|
||||
{
|
||||
CodePragma possible_end_region = cast(CodePragma, entry_iter);
|
||||
if ( possible_end_region->Content.contains(endregion_sig) ) {
|
||||
// body.append(possible_end_region);
|
||||
continue_for = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
body.append(entry_iter);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#define GEN_IMPLEMENTATION
|
||||
#include "gen/gen.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
// init();
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
# Singleheader
|
||||
|
||||
Creates a single header file version of the library using `gen.singleheader.cpp`.
|
||||
Creates a single header file version of the library using `singleheader.cpp`.
|
||||
Follows the same convention seen in the gb, stb, and zpl libraries.
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
gencpp: An attempt at "simple" staged metaprogramming for c/c++.
|
||||
|
||||
See Readme.md for more information from the project repository.
|
||||
|
||||
Public Address:
|
||||
https://github.com/Ed94/gencpp
|
||||
|
||||
This is a single header variant of the library.
|
||||
Define GEN_IMPLEMENTATION before including this file in a single compilation unit.
|
||||
|
||||
! ----------------------------------------------------------------------- VERSION: v0.20-Alpha !
|
||||
! ============================================================================================ !
|
||||
! WARNING: THIS IS AN ALPHA VERSION OF THE LIBRARY, USE AT YOUR OWN DISCRETION !
|
||||
! NEVER DO CODE GENERATION WITHOUT AT LEAST HAVING CONTENT IN A CODEBASE UNDER VERSION CONTROL !
|
||||
! ============================================================================================ !
|
||||
*/
|
||||
#if ! defined(GEN_DONT_ENFORCE_GEN_TIME_GUARD) && ! defined(GEN_TIME)
|
||||
# error Gen.hpp : GEN_TIME not defined
|
||||
#endif
|
||||
@@ -155,7 +155,7 @@ int gen_main()
|
||||
Code inlines = scan_file( project_dir "components/inlines.hpp" );
|
||||
Code header_end = scan_file( project_dir "components/header_end.hpp" );
|
||||
|
||||
CodeBody ecode = gen_ecode ( project_dir "enums/ECode.csv" );
|
||||
CodeBody ecode = gen_ecode ( project_dir "enums/ECodeTypes.csv" );
|
||||
CodeBody eoperator = gen_eoperator ( project_dir "enums/EOperator.csv" );
|
||||
CodeBody especifier = gen_especifier( project_dir "enums/ESpecifier.csv" );
|
||||
CodeBody ast_inlines = gen_ast_inlines();
|
||||
+6
@@ -7,6 +7,12 @@
|
||||
https://github.com/Ed94/gencpp
|
||||
|
||||
This is a variant intended for use with Unreal Engine 5
|
||||
|
||||
! ----------------------------------------------------------------------- VERSION: v0.20-Alpha !
|
||||
! ============================================================================================ !
|
||||
! WARNING: THIS IS AN ALPHA VERSION OF THE LIBRARY, USE AT YOUR OWN DISCRETION !
|
||||
! NEVER DO CODE GENERATION WITHOUT AT LEAST HAVING CONTENT IN A CODEBASE UNDER VERSION CONTROL !
|
||||
! ============================================================================================ !
|
||||
*/
|
||||
#if ! defined(GEN_DONT_ENFORCE_GEN_TIME_GUARD) && ! defined(GEN_TIME)
|
||||
# error Gen.hpp : GEN_TIME not defined
|
||||
@@ -217,7 +217,7 @@ int gen_main()
|
||||
Code inlines = scan_file( project_dir "components/inlines.hpp" );
|
||||
Code header_end = scan_file( project_dir "components/header_end.hpp" );
|
||||
|
||||
CodeBody ecode = gen_ecode ( project_dir "enums/ECode.csv" );
|
||||
CodeBody ecode = gen_ecode ( project_dir "enums/ECodeTypes.csv" );
|
||||
CodeBody eoperator = gen_eoperator ( project_dir "enums/EOperator.csv" );
|
||||
CodeBody especifier = gen_especifier( project_dir "enums/ESpecifier.csv" );
|
||||
CodeBody ast_inlines = gen_ast_inlines();
|
||||
+2
-1
@@ -10,7 +10,7 @@
|
||||
<IsVirtual>false</IsVirtual>
|
||||
<IsFolder>false</IsFolder>
|
||||
<BuildCommand>pwsh ./scripts/build.ps1 msvc debug bootstrap</BuildCommand>
|
||||
<RebuildCommand></RebuildCommand>
|
||||
<RebuildCommand>pwsh ./scripts/build.ps1 msvc debug c_library</RebuildCommand>
|
||||
<BuildFileCommand></BuildFileCommand>
|
||||
<CleanCommand>pwsh ./scripts/clean.ps1</CleanCommand>
|
||||
<BuildWorkingDirectory></BuildWorkingDirectory>
|
||||
@@ -48,6 +48,7 @@
|
||||
<Define>GEN_EXECUTION_EXPRESSION_SUPPORT</Define>
|
||||
<Define>GEN_BENCHMARK</Define>
|
||||
<Define>GEN_COMPILER_MSVC</Define>
|
||||
<Define>GEN_IMPLEMENTATION</Define>
|
||||
</Defines>
|
||||
<ConfigProperties>
|
||||
<ConfigAndPlatform>
|
||||
|
||||
@@ -257,6 +257,7 @@
|
||||
<None Include="test\Readme.md" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="gen_c_library\gen\gen.h" />
|
||||
<ClInclude Include="project\auxillary\builder.hpp" />
|
||||
<ClInclude Include="project\auxillary\editor.hpp" />
|
||||
<ClInclude Include="project\auxillary\scanner.hpp" />
|
||||
|
||||
@@ -30,6 +30,13 @@ Feature Macros:
|
||||
* `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.
|
||||
|
||||
@@ -13,7 +13,7 @@ Builder Builder::open( char const* path )
|
||||
return result;
|
||||
}
|
||||
|
||||
result.Buffer = String::make_reserve( GlobalAllocator, Builder_StrBufferReserve );
|
||||
result.Buffer = string_make_reserve( GlobalAllocator, Builder_StrBufferReserve );
|
||||
|
||||
// log_fmt("$Builder - Opened file: %s\n", result.File.filename );
|
||||
return result;
|
||||
@@ -21,15 +21,15 @@ Builder Builder::open( char const* path )
|
||||
|
||||
void Builder::pad_lines( s32 num )
|
||||
{
|
||||
Buffer.append( "\n" );
|
||||
string_append_strc( & Buffer, txt("\n") );
|
||||
}
|
||||
|
||||
void Builder::print( Code code )
|
||||
{
|
||||
String str = code->to_string();
|
||||
String str = code_to_string(code);
|
||||
// const ssize len = str.length();
|
||||
// log_fmt( "%s - print: %.*s\n", File.filename, len > 80 ? 80 : len, str.Data );
|
||||
Buffer.append( str );
|
||||
string_append_string( & Buffer, str );
|
||||
}
|
||||
|
||||
void Builder::print_fmt( char const* fmt, ... )
|
||||
@@ -43,17 +43,17 @@ void Builder::print_fmt( char const* fmt, ... )
|
||||
va_end( va );
|
||||
|
||||
// log_fmt( "$%s - print_fmt: %.*s\n", File.filename, res > 80 ? 80 : res, buf );
|
||||
Buffer.append( buf, res );
|
||||
string_append_c_str_len( (String*) & Buffer, (char const*)buf, res);
|
||||
}
|
||||
|
||||
void Builder::write()
|
||||
{
|
||||
b32 result = file_write( & File, Buffer, Buffer.length() );
|
||||
b32 result = file_write( & File, Buffer, string_length(Buffer) );
|
||||
|
||||
if ( result == false )
|
||||
log_failure("gen::File::write - Failed to write to file: %s\n", file_name( & File ) );
|
||||
|
||||
log_fmt( "Generated: %s\n", File.filename );
|
||||
file_close( & File );
|
||||
Buffer.free();
|
||||
string_free(& Buffer);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
# pragma once
|
||||
# include "../gen.hpp"
|
||||
#endif
|
||||
|
||||
/*
|
||||
Explicitly generates a resolved definition of a cpp template definition.
|
||||
|
||||
TODO(Ed): Needs implementing for the C-library variant.
|
||||
TODO(Ed): We need a non <token> syntax subst implemtnation for Strings for this to work. It must subst keywords directly based on template parameter names.
|
||||
|
||||
This is only meant to be used on relatively trivial templates, where the type or numeric is mostly a 'duck' type.
|
||||
It cannot parse complex template parameters.
|
||||
|
||||
The varadic args should correspond 1:1 with the type of objects the generator expects from the template's parameters.alignas.
|
||||
*/
|
||||
|
||||
CodeOperator gen_operator_template( CodeTemplate template, ... );
|
||||
CodeFn gen_func_template( CodeTemplate template, ... );
|
||||
Code gen_class_struct_template( CodeTemplate template, ... );
|
||||
|
||||
Code gen_template( CodeTemplate template, ... );
|
||||
Code gen_template( StrC template, StrC instantiation );
|
||||
@@ -23,9 +23,9 @@ Code scan_file( char const* path )
|
||||
GEN_FATAL("scan_file: %s is empty", path );
|
||||
}
|
||||
|
||||
String str = String::make_reserve( GlobalAllocator, fsize );
|
||||
String str = string_make_reserve( GlobalAllocator, fsize );
|
||||
file_read( & file, str, fsize );
|
||||
str.get_header().Length = fsize;
|
||||
string_get_header(str)->Length = fsize;
|
||||
|
||||
// Skip GEN_INTELLISENSE_DIRECTIVES preprocessor blocks
|
||||
// Its designed so that the directive should be the first thing in the file.
|
||||
@@ -39,7 +39,7 @@ Code scan_file( char const* path )
|
||||
const StrC def_intellisense = txt("GEN_INTELLISENSE_DIRECTIVES" );
|
||||
|
||||
bool found_directive = false;
|
||||
char const* scanner = str.Data;
|
||||
char const* scanner = (char const*)str;
|
||||
s32 left = fsize;
|
||||
while ( left )
|
||||
{
|
||||
@@ -52,7 +52,7 @@ Code scan_file( char const* path )
|
||||
|
||||
if ( ! found_directive )
|
||||
{
|
||||
if ( left && str_compare( scanner, directive_start.Ptr, directive_start.Len ) == matched )
|
||||
if ( left && str_compare_len( scanner, directive_start.Ptr, directive_start.Len ) == matched )
|
||||
{
|
||||
scanner += directive_start.Len;
|
||||
left -= directive_start.Len;
|
||||
@@ -60,7 +60,7 @@ Code scan_file( char const* path )
|
||||
while ( left && char_is_space( current ) )
|
||||
move_fwd();
|
||||
|
||||
if ( left && str_compare( scanner, def_intellisense.Ptr, def_intellisense.Len ) == matched )
|
||||
if ( left && str_compare_len( scanner, def_intellisense.Ptr, def_intellisense.Len ) == matched )
|
||||
{
|
||||
scanner += def_intellisense.Len;
|
||||
left -= def_intellisense.Len;
|
||||
@@ -80,7 +80,7 @@ Code scan_file( char const* path )
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( left && str_compare( scanner, directive_end.Ptr, directive_end.Len ) == matched )
|
||||
if ( left && str_compare_len( scanner, directive_end.Ptr, directive_end.Len ) == matched )
|
||||
{
|
||||
scanner += directive_end.Len;
|
||||
left -= directive_end.Len;
|
||||
@@ -94,19 +94,18 @@ Code scan_file( char const* path )
|
||||
move_fwd();
|
||||
|
||||
// sptr skip_size = fsize - left;
|
||||
if ( (scanner + 2) >= ( str.Data + fsize ) )
|
||||
if ( (scanner + 2) >= ( (char const*) str + fsize ) )
|
||||
{
|
||||
mem_move( str, scanner, left );
|
||||
str.get_header().Length = left;
|
||||
string_get_header(str)->Length = left;
|
||||
break;
|
||||
}
|
||||
|
||||
mem_move( str, scanner, left );
|
||||
str.get_header().Length = left;
|
||||
string_get_header(str)->Length = left;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
move_fwd();
|
||||
@@ -117,7 +116,7 @@ Code scan_file( char const* path )
|
||||
}
|
||||
|
||||
file_close( & file );
|
||||
return untyped_str( str );
|
||||
return untyped_str( string_to_strc(str) );
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
+22
-14
@@ -1,13 +1,16 @@
|
||||
#define GEN_DEFINE_LIBRARY_CODE_CONSTANTS
|
||||
#define GEN_ENFORCE_STRONG_CODE_TYPES
|
||||
#define GEN_EXPOSE_BACKEND
|
||||
#define GEN_C_LIKE_CPP 1
|
||||
#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"
|
||||
@@ -24,20 +27,20 @@ constexpr char const* generation_notice =
|
||||
|
||||
void format_file( char const* path )
|
||||
{
|
||||
String resolved_path = String::make(GlobalAllocator, to_str(path));
|
||||
String resolved_path = string_make_strc(GlobalAllocator, to_strc_from_c_str(path));
|
||||
|
||||
String style_arg = String::make(GlobalAllocator, txt("-style=file:"));
|
||||
style_arg.append("../scripts/.clang-format ");
|
||||
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 "clang-format "
|
||||
#define cf_format_inplace "-i "
|
||||
#define cf_verbose "-verbose "
|
||||
String command = String::make( GlobalAllocator, clang_format );
|
||||
command.append( cf_format_inplace );
|
||||
command.append( cf_verbose );
|
||||
command.append( style_arg );
|
||||
command.append( resolved_path );
|
||||
#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");
|
||||
@@ -62,6 +65,8 @@ 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" );
|
||||
|
||||
@@ -141,7 +146,7 @@ int gen_main()
|
||||
def_include(txt("components/types.hpp")),
|
||||
preprocess_endif,
|
||||
fmt_newline,
|
||||
untyped_str( to_str(generation_notice) )
|
||||
untyped_str( to_strc_from_c_str(generation_notice) )
|
||||
));
|
||||
|
||||
// gen.hpp
|
||||
@@ -155,7 +160,7 @@ int gen_main()
|
||||
Code inlines = scan_file( "components/inlines.hpp" );
|
||||
Code header_end = scan_file( "components/header_end.hpp" );
|
||||
|
||||
CodeBody ecode = gen_ecode ( "enums/ECode.csv" );
|
||||
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();
|
||||
@@ -239,7 +244,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)) );
|
||||
//CodeNS nspaced_etoktype = def_namespace( name(parser), def_namespace_body( args(etoktype)) );
|
||||
CodeBody nspaced_etoktype = def_global_body( args(
|
||||
etoktype
|
||||
));
|
||||
|
||||
Builder
|
||||
src = Builder::open( "gen/gen.cpp" );
|
||||
|
||||
+603
-574
File diff suppressed because it is too large
Load Diff
+228
-274
@@ -6,6 +6,18 @@
|
||||
#include "gen/especifier.hpp"
|
||||
#endif
|
||||
|
||||
/*
|
||||
______ ______ ________ __ __ ______ __
|
||||
/ \ / \| \ | \ | \ / \ | \
|
||||
| ▓▓▓▓▓▓\ ▓▓▓▓▓▓\\▓▓▓▓▓▓▓▓ | ▓▓\ | ▓▓ | ▓▓▓▓▓▓\ ______ ____| ▓▓ ______
|
||||
| ▓▓__| ▓▓ ▓▓___\▓▓ | ▓▓ | ▓▓▓\| ▓▓ | ▓▓ \▓▓/ \ / ▓▓/ \
|
||||
| ▓▓ ▓▓\▓▓ \ | ▓▓ | ▓▓▓▓\ ▓▓ | ▓▓ | ▓▓▓▓▓▓\ ▓▓▓▓▓▓▓ ▓▓▓▓▓▓\
|
||||
| ▓▓▓▓▓▓▓▓_\▓▓▓▓▓▓\ | ▓▓ | ▓▓\▓▓ ▓▓ | ▓▓ __| ▓▓ | ▓▓ ▓▓ | ▓▓ ▓▓ ▓▓
|
||||
| ▓▓ | ▓▓ \__| ▓▓ | ▓▓ | ▓▓ \▓▓▓▓ | ▓▓__/ \ ▓▓__/ ▓▓ ▓▓__| ▓▓ ▓▓▓▓▓▓▓▓
|
||||
| ▓▓ | ▓▓\▓▓ ▓▓ | ▓▓ | ▓▓ \▓▓▓ \▓▓ ▓▓\▓▓ ▓▓\▓▓ ▓▓\▓▓ \
|
||||
\▓▓ \▓▓ \▓▓▓▓▓▓ \▓▓ \▓▓ \▓▓ \▓▓▓▓▓▓ \▓▓▓▓▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓
|
||||
*/
|
||||
|
||||
struct AST;
|
||||
struct AST_Body;
|
||||
struct AST_Attributes;
|
||||
@@ -67,85 +79,131 @@ struct AST_Stmt_While;
|
||||
|
||||
struct AST_Struct;
|
||||
struct AST_Template;
|
||||
struct AST_Type;
|
||||
struct AST_Typename;
|
||||
struct AST_Typedef;
|
||||
struct AST_Union;
|
||||
struct AST_Using;
|
||||
struct AST_Var;
|
||||
|
||||
struct Code;
|
||||
struct CodeBody;
|
||||
// These are to offer ease of use and optionally strong type safety for the AST.
|
||||
struct CodeAttributes;
|
||||
// struct CodeBaseClass;
|
||||
struct CodeComment;
|
||||
struct CodeClass;
|
||||
struct CodeConstructor;
|
||||
struct CodeDefine;
|
||||
struct CodeDestructor;
|
||||
struct CodeEnum;
|
||||
struct CodeExec;
|
||||
struct CodeExtern;
|
||||
struct CodeInclude;
|
||||
struct CodeFriend;
|
||||
struct CodeFn;
|
||||
struct CodeModule;
|
||||
struct CodeNS;
|
||||
struct CodeOperator;
|
||||
struct CodeOpCast;
|
||||
struct CodeParam;
|
||||
struct CodePreprocessCond;
|
||||
struct CodePragma;
|
||||
struct CodeSpecifiers;
|
||||
|
||||
#if GEN_EXECUTION_EXPRESSION_SUPPORT
|
||||
struct CodeExpr;
|
||||
struct CodeExpr_Assign;
|
||||
struct CodeExpr_Alignof;
|
||||
struct CodeExpr_Binary;
|
||||
struct CodeExpr_CStyleCast;
|
||||
struct CodeExpr_FunctionalCast;
|
||||
struct CodeExpr_CppCast;
|
||||
struct CodeExpr_Element;
|
||||
struct CodeExpr_ProcCall;
|
||||
struct CodeExpr_Decltype;
|
||||
struct CodeExpr_Comma;
|
||||
struct CodeExpr_AMS; // Access Member Symbol
|
||||
struct CodeExpr_Sizeof;
|
||||
struct CodeExpr_Subscript;
|
||||
struct CodeExpr_Ternary;
|
||||
struct CodeExpr_UnaryPrefix;
|
||||
struct CodeExpr_UnaryPostfix;
|
||||
|
||||
struct CodeStmt;
|
||||
struct CodeStmt_Break;
|
||||
struct CodeStmt_Case;
|
||||
struct CodeStmt_Continue;
|
||||
struct CodeStmt_Decl;
|
||||
struct CodeStmt_Do;
|
||||
struct CodeStmt_Expr;
|
||||
struct CodeStmt_Else;
|
||||
struct CodeStmt_If;
|
||||
struct CodeStmt_For;
|
||||
struct CodeStmt_Goto;
|
||||
struct CodeStmt_Label;
|
||||
struct CodeStmt_Switch;
|
||||
struct CodeStmt_While;
|
||||
#if GEN_COMPILER_C
|
||||
#define Define_Code(Type) typedef AST_##Type* Code##Type
|
||||
#else
|
||||
#define Define_Code(Type) struct Code##Type
|
||||
#endif
|
||||
|
||||
struct CodeStruct;
|
||||
struct CodeTemplate;
|
||||
struct CodeType;
|
||||
struct CodeTypedef;
|
||||
struct CodeUnion;
|
||||
struct CodeUsing;
|
||||
struct CodeVar;
|
||||
#if GEN_COMPILER_C
|
||||
typedef AST* Code;
|
||||
#else
|
||||
struct Code;
|
||||
#endif
|
||||
|
||||
Define_Code(Body);
|
||||
// These are to offer ease of use and optionally strong type safety for the AST.
|
||||
Define_Code(Attributes);
|
||||
// struct CodeBaseClass;
|
||||
Define_Code(Comment);
|
||||
Define_Code(Class);
|
||||
Define_Code(Constructor);
|
||||
Define_Code(Define);
|
||||
Define_Code(Destructor);
|
||||
Define_Code(Enum);
|
||||
Define_Code(Exec);
|
||||
Define_Code(Extern);
|
||||
Define_Code(Include);
|
||||
Define_Code(Friend);
|
||||
Define_Code(Fn);
|
||||
Define_Code(Module);
|
||||
Define_Code(NS);
|
||||
Define_Code(Operator);
|
||||
Define_Code(OpCast);
|
||||
Define_Code(Param);
|
||||
Define_Code(PreprocessCond);
|
||||
Define_Code(Pragma);
|
||||
Define_Code(Specifiers);
|
||||
|
||||
#if GEN_EXECUTION_EXPRESSION_SUPPORT
|
||||
Define_Code(Expr);
|
||||
Define_Code(Expr_Assign);
|
||||
Define_Code(Expr_Alignof);
|
||||
Define_Code(Expr_Binary);
|
||||
Define_Code(Expr_CStyleCast);
|
||||
Define_Code(Expr_FunctionalCast);
|
||||
Define_Code(Expr_CppCast);
|
||||
Define_Code(Expr_Element);
|
||||
Define_Code(Expr_ProcCall);
|
||||
Define_Code(Expr_Decltype);
|
||||
Define_Code(Expr_Comma);
|
||||
Define_Code(Expr_AMS); // Access Member Symbol
|
||||
Define_Code(Expr_Sizeof);
|
||||
Define_Code(Expr_Subscript);
|
||||
Define_Code(Expr_Ternary);
|
||||
Define_Code(Expr_UnaryPrefix);
|
||||
Define_Code(Expr_UnaryPostfix);
|
||||
|
||||
Define_Code(Stmt);
|
||||
Define_Code(Stmt_Break);
|
||||
Define_Code(Stmt_Case);
|
||||
Define_Code(Stmt_Continue);
|
||||
Define_Code(Stmt_Decl);
|
||||
Define_Code(Stmt_Do);
|
||||
Define_Code(Stmt_Expr);
|
||||
Define_Code(Stmt_Else);
|
||||
Define_Code(Stmt_If);
|
||||
Define_Code(Stmt_For);
|
||||
Define_Code(Stmt_Goto);
|
||||
Define_Code(Stmt_Label);
|
||||
Define_Code(Stmt_Switch);
|
||||
Define_Code(Stmt_While);
|
||||
#endif
|
||||
|
||||
Define_Code(Struct);
|
||||
Define_Code(Template);
|
||||
Define_Code(Typename);
|
||||
Define_Code(Typedef);
|
||||
Define_Code(Union);
|
||||
Define_Code(Using);
|
||||
Define_Code(Var);
|
||||
|
||||
#undef Define_Code
|
||||
|
||||
GEN_NS_PARSER_BEGIN
|
||||
|
||||
namespace parser
|
||||
{
|
||||
struct Token;
|
||||
}
|
||||
|
||||
GEN_NS_PARSER_END
|
||||
|
||||
#if GEN_COMPILER_CPP
|
||||
// Note(Ed): This is to alleviate an edge case with parsing usings or typedefs where I don't really have it setup
|
||||
// to parse a 'namespace' macro or a type with a macro.
|
||||
// I have ideas for ways to pack that into the typedef/using ast, but for now just keeping it like this
|
||||
#define ParserTokenType GEN_NS_PARSER Token
|
||||
typedef ParserTokenType Token;
|
||||
#undef ParserTokenType
|
||||
#endif
|
||||
|
||||
#if GEN_COMPILER_CPP
|
||||
template< class Type> forceinline Type tmpl_cast( Code self ) { return * rcast( Type*, & self ); }
|
||||
#endif
|
||||
|
||||
#pragma region Code C-Interface
|
||||
|
||||
void code_append (Code code, Code other );
|
||||
StrC code_debug_str (Code code);
|
||||
Code code_duplicate (Code code);
|
||||
Code* code_entry (Code code, u32 idx );
|
||||
bool code_has_entries (Code code);
|
||||
bool code_is_body (Code code);
|
||||
bool code_is_equal (Code code, Code other);
|
||||
bool code_is_valid (Code code);
|
||||
void code_set_global (Code code);
|
||||
String code_to_string (Code self );
|
||||
void code_to_string_ptr(Code self, String* result );
|
||||
StrC code_type_str (Code self );
|
||||
bool code_validate_body(Code self );
|
||||
|
||||
#pragma endregion Code C-Interface
|
||||
|
||||
#if GEN_COMPILER_CPP
|
||||
/*
|
||||
AST* wrapper
|
||||
- Not constantly have to append the '*' as this is written often..
|
||||
@@ -153,39 +211,38 @@ namespace parser
|
||||
*/
|
||||
struct Code
|
||||
{
|
||||
# pragma region Statics
|
||||
// Used to identify ASTs that should always be duplicated. (Global constant ASTs)
|
||||
static Code Global;
|
||||
|
||||
// Used to identify invalid generated code.
|
||||
static Code Invalid;
|
||||
# pragma endregion Statics
|
||||
AST* ast;
|
||||
|
||||
# define Using_Code( Typename ) \
|
||||
char const* debug_str(); \
|
||||
Code duplicate(); \
|
||||
bool is_equal( Code other ); \
|
||||
bool is_valid(); \
|
||||
void set_global(); \
|
||||
String to_string(); \
|
||||
Typename& operator = ( AST* other ); \
|
||||
Typename& operator = ( Code other ); \
|
||||
bool operator ==( Code other ); \
|
||||
bool operator !=( Code other ); \
|
||||
forceinline StrC debug_str() { return code_debug_str(* this); } \
|
||||
forceinline Code duplicate() { return code_duplicate(* this); } \
|
||||
forceinline bool is_equal( Code other ) { return code_is_equal(* this, other); } \
|
||||
forceinline bool is_body() { return code_is_body(* this); } \
|
||||
forceinline bool is_valid() { return code_is_valid(* this); } \
|
||||
forceinline void set_global() { return code_set_global(* this); }
|
||||
|
||||
# define Using_CodeOps( Typename ) \
|
||||
forceinline Typename& operator = ( Code other ); \
|
||||
forceinline bool operator ==( Code other ) { return (AST*)ast == other.ast; } \
|
||||
forceinline bool operator !=( Code other ) { return (AST*)ast != other.ast; } \
|
||||
forceinline bool operator ==(std::nullptr_t) const { return ast == nullptr; } \
|
||||
forceinline bool operator !=(std::nullptr_t) const { return ast != nullptr; } \
|
||||
operator bool();
|
||||
|
||||
#if ! GEN_C_LIKE_CPP
|
||||
Using_Code( Code );
|
||||
forceinline void append(Code other) { return code_append(* this, other); }
|
||||
forceinline Code* entry(u32 idx) { return code_entry(* this, idx); }
|
||||
forceinline bool has_entries() { return code_has_entries(* this); }
|
||||
forceinline String to_string() { return code_to_string(* this); }
|
||||
forceinline void to_string(String& result) { return code_to_string_ptr(* this, & result); }
|
||||
forceinline StrC type_str() { return code_type_str(* this); }
|
||||
forceinline bool validate_body() { return code_validate_body(*this); }
|
||||
#endif
|
||||
|
||||
template< class Type >
|
||||
forceinline Type cast()
|
||||
{
|
||||
return * rcast( Type*, this );
|
||||
}
|
||||
Using_CodeOps( Code );
|
||||
forceinline AST* operator ->() { return ast; }
|
||||
|
||||
AST* operator ->()
|
||||
{
|
||||
return ast;
|
||||
}
|
||||
Code& operator ++();
|
||||
|
||||
// TODO(Ed) : Remove this overload.
|
||||
@@ -200,8 +257,6 @@ struct Code
|
||||
return *this;
|
||||
}
|
||||
|
||||
AST* ast;
|
||||
|
||||
#ifdef GEN_ENFORCE_STRONG_CODE_TYPES
|
||||
# define operator explicit operator
|
||||
#endif
|
||||
@@ -229,232 +284,131 @@ struct Code
|
||||
operator CodeSpecifiers() const;
|
||||
operator CodeStruct() const;
|
||||
operator CodeTemplate() const;
|
||||
operator CodeType() const;
|
||||
operator CodeTypename() const;
|
||||
operator CodeTypedef() const;
|
||||
operator CodeUnion() const;
|
||||
operator CodeUsing() const;
|
||||
operator CodeVar() const;
|
||||
#undef operator
|
||||
};
|
||||
#endif
|
||||
|
||||
#pragma region Statics
|
||||
// Used to identify ASTs that should always be duplicated. (Global constant ASTs)
|
||||
extern Code Code_Global;
|
||||
|
||||
// Used to identify invalid generated code.
|
||||
extern Code Code_Invalid;
|
||||
#pragma endregion Statics
|
||||
|
||||
struct Code_POD
|
||||
{
|
||||
AST* ast;
|
||||
};
|
||||
|
||||
static_assert( sizeof(Code) == sizeof(Code_POD), "ERROR: Code is not POD" );
|
||||
|
||||
// Desired width of the AST data structure.
|
||||
constexpr int const AST_POD_Size = 128;
|
||||
|
||||
constexpr static
|
||||
int AST_ArrSpecs_Cap =
|
||||
(
|
||||
AST_POD_Size
|
||||
- sizeof(Code)
|
||||
- sizeof(StringCached)
|
||||
- sizeof(Code) * 2
|
||||
- sizeof(Token*)
|
||||
- sizeof(Code)
|
||||
- sizeof(CodeType)
|
||||
- sizeof(ModuleFlag)
|
||||
- sizeof(u32)
|
||||
)
|
||||
/ sizeof(Specifier) - 1;
|
||||
|
||||
/*
|
||||
Simple AST POD with functionality to seralize into C++ syntax.
|
||||
*/
|
||||
struct AST
|
||||
{
|
||||
# pragma region Member Functions
|
||||
void append ( AST* other );
|
||||
char const* debug_str ();
|
||||
AST* duplicate ();
|
||||
Code& entry ( u32 idx );
|
||||
bool has_entries();
|
||||
bool is_equal ( AST* other );
|
||||
char const* type_str();
|
||||
bool validate_body();
|
||||
|
||||
String to_string();
|
||||
|
||||
neverinline
|
||||
void to_string( String& result );
|
||||
|
||||
template< class Type >
|
||||
forceinline Type cast()
|
||||
{
|
||||
return * this;
|
||||
}
|
||||
|
||||
operator Code();
|
||||
operator CodeBody();
|
||||
operator CodeAttributes();
|
||||
// operator CodeBaseClass();
|
||||
operator CodeComment();
|
||||
operator CodeConstructor();
|
||||
operator CodeDestructor();
|
||||
operator CodeClass();
|
||||
operator CodeDefine();
|
||||
operator CodeEnum();
|
||||
operator CodeExec();
|
||||
operator CodeExtern();
|
||||
operator CodeInclude();
|
||||
operator CodeFriend();
|
||||
operator CodeFn();
|
||||
operator CodeModule();
|
||||
operator CodeNS();
|
||||
operator CodeOperator();
|
||||
operator CodeOpCast();
|
||||
operator CodeParam();
|
||||
operator CodePragma();
|
||||
operator CodePreprocessCond();
|
||||
operator CodeSpecifiers();
|
||||
operator CodeStruct();
|
||||
operator CodeTemplate();
|
||||
operator CodeType();
|
||||
operator CodeTypedef();
|
||||
operator CodeUnion();
|
||||
operator CodeUsing();
|
||||
operator CodeVar();
|
||||
# pragma endregion Member Functions
|
||||
|
||||
constexpr static
|
||||
int ArrSpecs_Cap =
|
||||
(
|
||||
AST_POD_Size
|
||||
- sizeof(AST*) * 3
|
||||
- sizeof(parser::Token*)
|
||||
- sizeof(AST*)
|
||||
- sizeof(StringCached)
|
||||
- sizeof(CodeT)
|
||||
- sizeof(ModuleFlag)
|
||||
- sizeof(int)
|
||||
)
|
||||
/ sizeof(int) - 1; // -1 for 4 extra bytes
|
||||
|
||||
union {
|
||||
struct
|
||||
{
|
||||
AST* InlineCmt; // Class, Constructor, Destructor, Enum, Friend, Functon, Operator, OpCast, Struct, Typedef, Using, Variable
|
||||
AST* Attributes; // Class, Enum, Function, Struct, Typedef, Union, Using, Variable
|
||||
AST* Specs; // Destructor, Function, Operator, Typename, Variable
|
||||
Code InlineCmt; // Class, Constructor, Destructor, Enum, Friend, Functon, Operator, OpCast, Struct, Typedef, Using, Variable
|
||||
Code Attributes; // Class, Enum, Function, Struct, Typedef, Union, Using, Variable
|
||||
Code Specs; // Destructor, Function, Operator, Typename, Variable
|
||||
union {
|
||||
AST* InitializerList; // Constructor
|
||||
AST* ParentType; // Class, Struct, ParentType->Next has a possible list of interfaces.
|
||||
AST* ReturnType; // Function, Operator, Typename
|
||||
AST* UnderlyingType; // Enum, Typedef
|
||||
AST* ValueType; // Parameter, Variable
|
||||
Code InitializerList; // Constructor
|
||||
Code ParentType; // Class, Struct, ParentType->Next has a possible list of interfaces.
|
||||
Code ReturnType; // Function, Operator, Typename
|
||||
Code UnderlyingType; // Enum, Typedef
|
||||
Code ValueType; // Parameter, Variable
|
||||
};
|
||||
union {
|
||||
AST* Macro; // Parameter
|
||||
AST* BitfieldSize; // Variable (Class/Struct Data Member)
|
||||
AST* Params; // Constructor, Function, Operator, Template, Typename
|
||||
Code Macro; // Parameter
|
||||
Code BitfieldSize; // Variable (Class/Struct Data Member)
|
||||
Code Params; // Constructor, Function, Operator, Template, Typename
|
||||
Code UnderlyingTypeMacro; // Enum
|
||||
};
|
||||
union {
|
||||
AST* ArrExpr; // Typename
|
||||
AST* Body; // Class, Constructor, Destructor, Enum, Friend, Function, Namespace, Struct, Union
|
||||
AST* Declaration; // Friend, Template
|
||||
AST* Value; // Parameter, Variable
|
||||
Code ArrExpr; // Typename
|
||||
Code Body; // Class, Constructor, Destructor, Enum, Friend, Function, Namespace, Struct, Union
|
||||
Code Declaration; // Friend, Template
|
||||
Code Value; // Parameter, Variable
|
||||
};
|
||||
union {
|
||||
AST* NextVar; // Variable; Possible way to handle comma separated variables declarations. ( , NextVar->Specs NextVar->Name NextVar->ArrExpr = NextVar->Value )
|
||||
AST* SuffixSpecs; // Only used with typenames, to store the function suffix if typename is function signature. ( May not be needed )
|
||||
AST* PostNameMacro; // Only used with parameters for specifically UE_REQUIRES (Thanks Unreal)
|
||||
Code NextVar; // Variable; Possible way to handle comma separated variables declarations. ( , NextVar->Specs NextVar->Name NextVar->ArrExpr = NextVar->Value )
|
||||
Code SuffixSpecs; // Only used with typenames, to store the function suffix if typename is function signature. ( May not be needed )
|
||||
Code PostNameMacro; // Only used with parameters for specifically UE_REQUIRES (Thanks Unreal)
|
||||
};
|
||||
};
|
||||
StringCached Content; // Attributes, Comment, Execution, Include
|
||||
struct {
|
||||
SpecifierT ArrSpecs[ArrSpecs_Cap]; // Specifiers
|
||||
AST* NextSpecs; // Specifiers; If ArrSpecs is full, then NextSpecs is used.
|
||||
Specifier ArrSpecs[AST_ArrSpecs_Cap]; // Specifiers
|
||||
Code NextSpecs; // Specifiers; If ArrSpecs is full, then NextSpecs is used.
|
||||
};
|
||||
};
|
||||
union {
|
||||
AST* Prev;
|
||||
AST* Front;
|
||||
AST* Last;
|
||||
};
|
||||
union {
|
||||
AST* Next;
|
||||
AST* Back;
|
||||
};
|
||||
parser::Token* Token; // Reference to starting token, only avaialble if it was derived from parsing.
|
||||
AST* Parent;
|
||||
StringCached Name;
|
||||
CodeT Type;
|
||||
union {
|
||||
Code Prev;
|
||||
Code Front;
|
||||
Code Last;
|
||||
};
|
||||
union {
|
||||
Code Next;
|
||||
Code Back;
|
||||
};
|
||||
Token* Token; // Reference to starting token, only avaialble if it was derived from parsing.
|
||||
Code Parent;
|
||||
CodeType Type;
|
||||
// CodeFlag CodeFlags;
|
||||
ModuleFlag ModuleFlags;
|
||||
union {
|
||||
b32 IsFunction; // Used by typedef to not serialize the name field.
|
||||
b32 IsParamPack; // Used by typename to know if type should be considered a parameter pack.
|
||||
OperatorT Op;
|
||||
AccessSpec ParentAccess;
|
||||
s32 NumEntries;
|
||||
s32 VarConstructorInit; // Used by variables to know that initialization is using a constructor expression instead of an assignment expression.
|
||||
};
|
||||
};
|
||||
|
||||
struct AST_POD
|
||||
{
|
||||
union {
|
||||
struct
|
||||
{
|
||||
AST* InlineCmt; // Class, Constructor, Destructor, Enum, Friend, Functon, Operator, OpCast, Struct, Typedef, Using, Variable
|
||||
AST* Attributes; // Class, Enum, Function, Struct, Typedef, Union, Using, Variable
|
||||
AST* Specs; // Destructor, Function, Operator, Typename, Variable
|
||||
union {
|
||||
AST* InitializerList; // Constructor
|
||||
AST* ParentType; // Class, Struct, ParentType->Next has a possible list of interfaces.
|
||||
AST* ReturnType; // Function, Operator, Typename
|
||||
AST* UnderlyingType; // Enum, Typedef
|
||||
AST* ValueType; // Parameter, Variable
|
||||
};
|
||||
union {
|
||||
AST* Macro; // Parameter
|
||||
AST* BitfieldSize; // Variable (Class/Struct Data Member)
|
||||
AST* Params; // Constructor, Function, Operator, Template, Typename
|
||||
};
|
||||
union {
|
||||
AST* ArrExpr; // Typename
|
||||
AST* Body; // Class, Constructr, Destructor, Enum, Friend, Function, Namespace, Struct, Union
|
||||
AST* Declaration; // Friend, Template
|
||||
AST* Value; // Parameter, Variable
|
||||
};
|
||||
union {
|
||||
AST* NextVar; // Variable; Possible way to handle comma separated variables declarations. ( , NextVar->Specs NextVar->Name NextVar->ArrExpr = NextVar->Value )
|
||||
AST* SuffixSpecs; // Only used with typenames, to store the function suffix if typename is function signature. ( May not be needed )
|
||||
AST* PostNameMacro; // Only used with parameters for specifically UE_REQUIRES (Thanks Unreal)
|
||||
};
|
||||
};
|
||||
StringCached Content; // Attributes, Comment, Execution, Include
|
||||
struct {
|
||||
SpecifierT ArrSpecs[AST::ArrSpecs_Cap]; // Specifiers
|
||||
AST* NextSpecs; // Specifiers; If ArrSpecs is full, then NextSpecs is used.
|
||||
b16 IsParamPack; // Used by typename to know if type should be considered a parameter pack.
|
||||
ETypenameTag TypeTag; // Used by typename to keep track of explicitly declared tags for the identifier (enum, struct, union)
|
||||
};
|
||||
};
|
||||
union {
|
||||
AST* Prev;
|
||||
AST* Front;
|
||||
AST* Last;
|
||||
};
|
||||
union {
|
||||
AST* Next;
|
||||
AST* Back;
|
||||
};
|
||||
parser::Token* Token; // Reference to starting token, only avaialble if it was derived from parsing.
|
||||
AST* Parent;
|
||||
StringCached Name;
|
||||
CodeT Type;
|
||||
CodeFlag CodeFlags;
|
||||
ModuleFlag ModuleFlags;
|
||||
union {
|
||||
b32 IsFunction; // Used by typedef to not serialize the name field.
|
||||
b32 IsParamPack; // Used by typename to know if type should be considered a parameter pack.
|
||||
OperatorT Op;
|
||||
Operator Op;
|
||||
AccessSpec ParentAccess;
|
||||
s32 NumEntries;
|
||||
s32 VarConstructorInit; // Used by variables to know that initialization is using a constructor expression instead of an assignment expression.
|
||||
};
|
||||
};
|
||||
static_assert( sizeof(AST) == AST_POD_Size, "ERROR: AST is not size of AST_POD_Size" );
|
||||
|
||||
struct test {
|
||||
SpecifierT ArrSpecs[AST::ArrSpecs_Cap]; // Specifiers
|
||||
AST* NextSpecs; // Specifiers; If ArrSpecs is full, then NextSpecs is used.
|
||||
};
|
||||
|
||||
constexpr int pls = sizeof(test);
|
||||
|
||||
// Its intended for the AST to have equivalent size to its POD.
|
||||
// All extra functionality within the AST namespace should just be syntatic sugar.
|
||||
static_assert( sizeof(AST) == sizeof(AST_POD), "ERROR: AST IS NOT POD" );
|
||||
static_assert( sizeof(AST_POD) == AST_POD_Size, "ERROR: AST POD is not size of AST_POD_Size" );
|
||||
#if GEN_COMPILER_CPP
|
||||
// Uses an implicitly overloaded cast from the AST to the desired code type.
|
||||
// Necessary if the user wants GEN_ENFORCE_STRONG_CODE_TYPES
|
||||
struct InvalidCode_ImplictCaster;
|
||||
#define InvalidCode (InvalidCode_ImplictCaster{})
|
||||
#else
|
||||
#define InvalidCode (void*){ (void*)Code_Invalid }
|
||||
#endif
|
||||
|
||||
#if GEN_COMPILER_CPP
|
||||
struct NullCode_ImplicitCaster;
|
||||
// Used when the its desired when omission is allowed in a definition.
|
||||
#define NoCode { nullptr }
|
||||
#define CodeInvalid (* Code::Invalid.ast) // Uses an implicitly overloaded cast from the AST to the desired code type.
|
||||
#define NullCode (NullCode_ImplicitCaster{})
|
||||
#else
|
||||
#define NullCode nullptr
|
||||
#endif
|
||||
|
||||
@@ -1,78 +1,78 @@
|
||||
# define GEN_AST_BODY_CLASS_UNALLOWED_TYPES \
|
||||
case PlatformAttributes: \
|
||||
case Class_Body: \
|
||||
case Enum_Body: \
|
||||
case Extern_Linkage: \
|
||||
case Function_Body: \
|
||||
case Function_Fwd: \
|
||||
case Global_Body: \
|
||||
case Namespace: \
|
||||
case Namespace_Body: \
|
||||
case Operator: \
|
||||
case Operator_Fwd: \
|
||||
case Parameters: \
|
||||
case Specifiers: \
|
||||
case Struct_Body: \
|
||||
case Typename:
|
||||
case CT_PlatformAttributes: \
|
||||
case CT_Class_Body: \
|
||||
case CT_Enum_Body: \
|
||||
case CT_Extern_Linkage: \
|
||||
case CT_Function_Body: \
|
||||
case CT_Function_Fwd: \
|
||||
case CT_Global_Body: \
|
||||
case CT_Namespace: \
|
||||
case CT_Namespace_Body: \
|
||||
case CT_Operator: \
|
||||
case CT_Operator_Fwd: \
|
||||
case CT_Parameters: \
|
||||
case CT_Specifiers: \
|
||||
case CT_Struct_Body: \
|
||||
case CT_Typename:
|
||||
# define GEN_AST_BODY_STRUCT_UNALLOWED_TYPES GEN_AST_BODY_CLASS_UNALLOWED_TYPES
|
||||
|
||||
# define GEN_AST_BODY_FUNCTION_UNALLOWED_TYPES \
|
||||
case Access_Public: \
|
||||
case Access_Protected: \
|
||||
case Access_Private: \
|
||||
case PlatformAttributes: \
|
||||
case Class_Body: \
|
||||
case Enum_Body: \
|
||||
case Extern_Linkage: \
|
||||
case Friend: \
|
||||
case Function_Body: \
|
||||
case Function_Fwd: \
|
||||
case Global_Body: \
|
||||
case Namespace: \
|
||||
case Namespace_Body: \
|
||||
case Operator: \
|
||||
case Operator_Fwd: \
|
||||
case Operator_Member: \
|
||||
case Operator_Member_Fwd: \
|
||||
case Parameters: \
|
||||
case Specifiers: \
|
||||
case Struct_Body: \
|
||||
case Typename:
|
||||
case CT_Access_Public: \
|
||||
case CT_Access_Protected: \
|
||||
case CT_Access_Private: \
|
||||
case CT_PlatformAttributes: \
|
||||
case CT_Class_Body: \
|
||||
case CT_Enum_Body: \
|
||||
case CT_Extern_Linkage: \
|
||||
case CT_Friend: \
|
||||
case CT_Function_Body: \
|
||||
case CT_Function_Fwd: \
|
||||
case CT_Global_Body: \
|
||||
case CT_Namespace: \
|
||||
case CT_Namespace_Body: \
|
||||
case CT_Operator: \
|
||||
case CT_Operator_Fwd: \
|
||||
case CT_Operator_Member: \
|
||||
case CT_Operator_Member_Fwd: \
|
||||
case CT_Parameters: \
|
||||
case CT_Specifiers: \
|
||||
case CT_Struct_Body: \
|
||||
case CT_Typename:
|
||||
|
||||
# define GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES \
|
||||
case Access_Public: \
|
||||
case Access_Protected: \
|
||||
case Access_Private: \
|
||||
case PlatformAttributes: \
|
||||
case Class_Body: \
|
||||
case Enum_Body: \
|
||||
case Execution: \
|
||||
case Friend: \
|
||||
case Function_Body: \
|
||||
case Namespace_Body: \
|
||||
case Operator_Member: \
|
||||
case Operator_Member_Fwd: \
|
||||
case Parameters: \
|
||||
case Specifiers: \
|
||||
case Struct_Body: \
|
||||
case Typename:
|
||||
case CT_Access_Public: \
|
||||
case CT_Access_Protected: \
|
||||
case CT_Access_Private: \
|
||||
case CT_PlatformAttributes: \
|
||||
case CT_Class_Body: \
|
||||
case CT_Enum_Body: \
|
||||
case CT_Execution: \
|
||||
case CT_Friend: \
|
||||
case CT_Function_Body: \
|
||||
case CT_Namespace_Body: \
|
||||
case CT_Operator_Member: \
|
||||
case CT_Operator_Member_Fwd: \
|
||||
case CT_Parameters: \
|
||||
case CT_Specifiers: \
|
||||
case CT_Struct_Body: \
|
||||
case CT_Typename:
|
||||
# define GEN_AST_BODY_EXPORT_UNALLOWED_TYPES GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES
|
||||
# define GEN_AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES
|
||||
|
||||
# define GEN_AST_BODY_NAMESPACE_UNALLOWED_TYPES \
|
||||
case Access_Public: \
|
||||
case Access_Protected: \
|
||||
case Access_Private: \
|
||||
case PlatformAttributes: \
|
||||
case Class_Body: \
|
||||
case Enum_Body: \
|
||||
case Execution: \
|
||||
case Friend: \
|
||||
case Function_Body: \
|
||||
case Namespace_Body: \
|
||||
case Operator_Member: \
|
||||
case Operator_Member_Fwd: \
|
||||
case Parameters: \
|
||||
case Specifiers: \
|
||||
case Struct_Body: \
|
||||
case Typename:
|
||||
case CT_Access_Public: \
|
||||
case CT_Access_Protected: \
|
||||
case CT_Access_Private: \
|
||||
case CT_PlatformAttributes: \
|
||||
case CT_Class_Body: \
|
||||
case CT_Enum_Body: \
|
||||
case CT_Execution: \
|
||||
case CT_Friend: \
|
||||
case CT_Function_Body: \
|
||||
case CT_Namespace_Body: \
|
||||
case CT_Operator_Member: \
|
||||
case CT_Operator_Member_Fwd: \
|
||||
case CT_Parameters: \
|
||||
case CT_Specifiers: \
|
||||
case CT_Struct_Body: \
|
||||
case CT_Typename:
|
||||
|
||||
+289
-265
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+673
-424
File diff suppressed because it is too large
Load Diff
+122
-1854
File diff suppressed because it is too large
Load Diff
@@ -5,76 +5,76 @@
|
||||
|
||||
// This file was generated automatially by gencpp's bootstrap.cpp (See: https://github.com/Ed94/gencpp)
|
||||
|
||||
namespace ECode
|
||||
enum CodeType : u32
|
||||
{
|
||||
enum Type : u32
|
||||
{
|
||||
Invalid,
|
||||
Untyped,
|
||||
NewLine,
|
||||
Comment,
|
||||
Access_Private,
|
||||
Access_Protected,
|
||||
Access_Public,
|
||||
PlatformAttributes,
|
||||
Class,
|
||||
Class_Fwd,
|
||||
Class_Body,
|
||||
Constructor,
|
||||
Constructor_Fwd,
|
||||
Destructor,
|
||||
Destructor_Fwd,
|
||||
Enum,
|
||||
Enum_Fwd,
|
||||
Enum_Body,
|
||||
Enum_Class,
|
||||
Enum_Class_Fwd,
|
||||
Execution,
|
||||
Export_Body,
|
||||
Extern_Linkage,
|
||||
Extern_Linkage_Body,
|
||||
Friend,
|
||||
Function,
|
||||
Function_Fwd,
|
||||
Function_Body,
|
||||
Global_Body,
|
||||
Module,
|
||||
Namespace,
|
||||
Namespace_Body,
|
||||
Operator,
|
||||
Operator_Fwd,
|
||||
Operator_Member,
|
||||
Operator_Member_Fwd,
|
||||
Operator_Cast,
|
||||
Operator_Cast_Fwd,
|
||||
Parameters,
|
||||
Preprocess_Define,
|
||||
Preprocess_Include,
|
||||
Preprocess_If,
|
||||
Preprocess_IfDef,
|
||||
Preprocess_IfNotDef,
|
||||
Preprocess_ElIf,
|
||||
Preprocess_Else,
|
||||
Preprocess_EndIf,
|
||||
Preprocess_Pragma,
|
||||
Specifiers,
|
||||
Struct,
|
||||
Struct_Fwd,
|
||||
Struct_Body,
|
||||
Template,
|
||||
Typedef,
|
||||
Typename,
|
||||
Union,
|
||||
Union_Body,
|
||||
Using,
|
||||
Using_Namespace,
|
||||
Variable,
|
||||
NumTypes
|
||||
CT_Invalid,
|
||||
CT_Untyped,
|
||||
CT_NewLine,
|
||||
CT_Comment,
|
||||
CT_Access_Private,
|
||||
CT_Access_Protected,
|
||||
CT_Access_Public,
|
||||
CT_PlatformAttributes,
|
||||
CT_Class,
|
||||
CT_Class_Fwd,
|
||||
CT_Class_Body,
|
||||
CT_Constructor,
|
||||
CT_Constructor_Fwd,
|
||||
CT_Destructor,
|
||||
CT_Destructor_Fwd,
|
||||
CT_Enum,
|
||||
CT_Enum_Fwd,
|
||||
CT_Enum_Body,
|
||||
CT_Enum_Class,
|
||||
CT_Enum_Class_Fwd,
|
||||
CT_Execution,
|
||||
CT_Export_Body,
|
||||
CT_Extern_Linkage,
|
||||
CT_Extern_Linkage_Body,
|
||||
CT_Friend,
|
||||
CT_Function,
|
||||
CT_Function_Fwd,
|
||||
CT_Function_Body,
|
||||
CT_Global_Body,
|
||||
CT_Module,
|
||||
CT_Namespace,
|
||||
CT_Namespace_Body,
|
||||
CT_Operator,
|
||||
CT_Operator_Fwd,
|
||||
CT_Operator_Member,
|
||||
CT_Operator_Member_Fwd,
|
||||
CT_Operator_Cast,
|
||||
CT_Operator_Cast_Fwd,
|
||||
CT_Parameters,
|
||||
CT_Preprocess_Define,
|
||||
CT_Preprocess_Include,
|
||||
CT_Preprocess_If,
|
||||
CT_Preprocess_IfDef,
|
||||
CT_Preprocess_IfNotDef,
|
||||
CT_Preprocess_ElIf,
|
||||
CT_Preprocess_Else,
|
||||
CT_Preprocess_EndIf,
|
||||
CT_Preprocess_Pragma,
|
||||
CT_Specifiers,
|
||||
CT_Struct,
|
||||
CT_Struct_Fwd,
|
||||
CT_Struct_Body,
|
||||
CT_Template,
|
||||
CT_Typedef,
|
||||
CT_Typename,
|
||||
CT_Union,
|
||||
CT_Union_Fwd,
|
||||
CT_Union_Body,
|
||||
CT_Using,
|
||||
CT_Using_Namespace,
|
||||
CT_Variable,
|
||||
CT_NumTypes,
|
||||
CT_UnderlyingType = GEN_U32_MAX
|
||||
};
|
||||
|
||||
inline StrC to_str( Type type )
|
||||
inline StrC codetype_to_str( CodeType type )
|
||||
{
|
||||
local_persist StrC lookup[] {
|
||||
local_persist StrC lookup[61] = {
|
||||
{ sizeof( "Invalid" ), "Invalid" },
|
||||
{ sizeof( "Untyped" ), "Untyped" },
|
||||
{ sizeof( "NewLine" ), "NewLine" },
|
||||
@@ -131,6 +131,7 @@ namespace ECode
|
||||
{ sizeof( "Typedef" ), "Typedef" },
|
||||
{ sizeof( "Typename" ), "Typename" },
|
||||
{ sizeof( "Union" ), "Union" },
|
||||
{ sizeof( "Union_Fwd" ), "Union_Fwd" },
|
||||
{ sizeof( "Union_Body" ), "Union_Body" },
|
||||
{ sizeof( "Using" ), "Using" },
|
||||
{ sizeof( "Using_Namespace" ), "Using_Namespace" },
|
||||
@@ -139,6 +140,80 @@ namespace ECode
|
||||
return lookup[type];
|
||||
}
|
||||
|
||||
} // namespace ECode
|
||||
inline StrC codetype_to_keyword_str( CodeType type )
|
||||
{
|
||||
local_persist StrC lookup[61] = {
|
||||
{ sizeof( "__NA__" ) - 1, "__NA__" },
|
||||
{ sizeof( "__NA__" ) - 1, "__NA__" },
|
||||
{ sizeof( "__NA__" ) - 1, "__NA__" },
|
||||
{ sizeof( "//" ) - 1, "//" },
|
||||
{ sizeof( "private" ) - 1, "private" },
|
||||
{ sizeof( "protected" ) - 1, "protected" },
|
||||
{ sizeof( "public" ) - 1, "public" },
|
||||
{ sizeof( "__NA__" ) - 1, "__NA__" },
|
||||
{ sizeof( "class" ) - 1, "class" },
|
||||
{ sizeof( "clsss" ) - 1, "clsss" },
|
||||
{ sizeof( "__NA__" ) - 1, "__NA__" },
|
||||
{ sizeof( "__NA__" ) - 1, "__NA__" },
|
||||
{ sizeof( "__NA__" ) - 1, "__NA__" },
|
||||
{ sizeof( "__NA__" ) - 1, "__NA__" },
|
||||
{ sizeof( "__NA__" ) - 1, "__NA__" },
|
||||
{ sizeof( "enum" ) - 1, "enum" },
|
||||
{ sizeof( "enum" ) - 1, "enum" },
|
||||
{ sizeof( "__NA__" ) - 1, "__NA__" },
|
||||
{ sizeof( "enum class" ) - 1, "enum class" },
|
||||
{ sizeof( "enum class" ) - 1, "enum class" },
|
||||
{ sizeof( "__NA__" ) - 1, "__NA__" },
|
||||
{ sizeof( "__NA__" ) - 1, "__NA__" },
|
||||
{ sizeof( "extern" ) - 1, "extern" },
|
||||
{ sizeof( "extern" ) - 1, "extern" },
|
||||
{ sizeof( "friend" ) - 1, "friend" },
|
||||
{ sizeof( "__NA__" ) - 1, "__NA__" },
|
||||
{ sizeof( "__NA__" ) - 1, "__NA__" },
|
||||
{ sizeof( "__NA__" ) - 1, "__NA__" },
|
||||
{ sizeof( "__NA__" ) - 1, "__NA__" },
|
||||
{ sizeof( "module" ) - 1, "module" },
|
||||
{ sizeof( "namespace" ) - 1, "namespace" },
|
||||
{ sizeof( "__NA__" ) - 1, "__NA__" },
|
||||
{ sizeof( "operator" ) - 1, "operator" },
|
||||
{ sizeof( "operator" ) - 1, "operator" },
|
||||
{ sizeof( "operator" ) - 1, "operator" },
|
||||
{ sizeof( "operator" ) - 1, "operator" },
|
||||
{ sizeof( "operator" ) - 1, "operator" },
|
||||
{ sizeof( "operator" ) - 1, "operator" },
|
||||
{ sizeof( "__NA__" ) - 1, "__NA__" },
|
||||
{ sizeof( "define" ) - 1, "define" },
|
||||
{ sizeof( "include" ) - 1, "include" },
|
||||
{ sizeof( "if" ) - 1, "if" },
|
||||
{ sizeof( "ifdef" ) - 1, "ifdef" },
|
||||
{ sizeof( "ifndef" ) - 1, "ifndef" },
|
||||
{ sizeof( "elif" ) - 1, "elif" },
|
||||
{ sizeof( "else" ) - 1, "else" },
|
||||
{ sizeof( "endif" ) - 1, "endif" },
|
||||
{ sizeof( "pragma" ) - 1, "pragma" },
|
||||
{ sizeof( "__NA__" ) - 1, "__NA__" },
|
||||
{ sizeof( "struct" ) - 1, "struct" },
|
||||
{ sizeof( "struct" ) - 1, "struct" },
|
||||
{ sizeof( "__NA__" ) - 1, "__NA__" },
|
||||
{ sizeof( "template" ) - 1, "template" },
|
||||
{ sizeof( "typedef" ) - 1, "typedef" },
|
||||
{ sizeof( "__NA__" ) - 1, "__NA__" },
|
||||
{ sizeof( "union" ) - 1, "union" },
|
||||
{ sizeof( "union" ) - 1, "union" },
|
||||
{ sizeof( "__NA__" ) - 1, "__NA__" },
|
||||
{ sizeof( "using" ) - 1, "using" },
|
||||
{ sizeof( "using namespace" ) - 1, "using namespace" },
|
||||
{ sizeof( "__NA__" ) - 1, "__NA__" },
|
||||
};
|
||||
return lookup[type];
|
||||
}
|
||||
|
||||
using CodeT = ECode::Type;
|
||||
forceinline StrC to_str( CodeType type )
|
||||
{
|
||||
return codetype_to_str( type );
|
||||
}
|
||||
|
||||
forceinline StrC to_keyword_str( CodeType type )
|
||||
{
|
||||
return codetype_to_keyword_str( type );
|
||||
}
|
||||
|
||||
@@ -5,63 +5,62 @@
|
||||
|
||||
// This file was generated automatially by gencpp's bootstrap.cpp (See: https://github.com/Ed94/gencpp)
|
||||
|
||||
namespace EOperator
|
||||
enum Operator : u32
|
||||
{
|
||||
enum Type : u32
|
||||
{
|
||||
Invalid,
|
||||
Assign,
|
||||
Assign_Add,
|
||||
Assign_Subtract,
|
||||
Assign_Multiply,
|
||||
Assign_Divide,
|
||||
Assign_Modulo,
|
||||
Assign_BAnd,
|
||||
Assign_BOr,
|
||||
Assign_BXOr,
|
||||
Assign_LShift,
|
||||
Assign_RShift,
|
||||
Increment,
|
||||
Decrement,
|
||||
Unary_Plus,
|
||||
Unary_Minus,
|
||||
UnaryNot,
|
||||
Add,
|
||||
Subtract,
|
||||
Multiply,
|
||||
Divide,
|
||||
Modulo,
|
||||
BNot,
|
||||
BAnd,
|
||||
BOr,
|
||||
BXOr,
|
||||
LShift,
|
||||
RShift,
|
||||
LAnd,
|
||||
LOr,
|
||||
LEqual,
|
||||
LNot,
|
||||
Lesser,
|
||||
Greater,
|
||||
LesserEqual,
|
||||
GreaterEqual,
|
||||
Subscript,
|
||||
Indirection,
|
||||
AddressOf,
|
||||
MemberOfPointer,
|
||||
PtrToMemOfPtr,
|
||||
FunctionCall,
|
||||
Comma,
|
||||
New,
|
||||
NewArray,
|
||||
Delete,
|
||||
DeleteArray,
|
||||
NumOps
|
||||
Op_Invalid,
|
||||
Op_Assign,
|
||||
Op_Assign_Add,
|
||||
Op_Assign_Subtract,
|
||||
Op_Assign_Multiply,
|
||||
Op_Assign_Divide,
|
||||
Op_Assign_Modulo,
|
||||
Op_Assign_BAnd,
|
||||
Op_Assign_BOr,
|
||||
Op_Assign_BXOr,
|
||||
Op_Assign_LShift,
|
||||
Op_Assign_RShift,
|
||||
Op_Increment,
|
||||
Op_Decrement,
|
||||
Op_Unary_Plus,
|
||||
Op_Unary_Minus,
|
||||
Op_UnaryNot,
|
||||
Op_Add,
|
||||
Op_Subtract,
|
||||
Op_Multiply,
|
||||
Op_Divide,
|
||||
Op_Modulo,
|
||||
Op_BNot,
|
||||
Op_BAnd,
|
||||
Op_BOr,
|
||||
Op_BXOr,
|
||||
Op_LShift,
|
||||
Op_RShift,
|
||||
Op_LAnd,
|
||||
Op_LOr,
|
||||
Op_LEqual,
|
||||
Op_LNot,
|
||||
Op_Lesser,
|
||||
Op_Greater,
|
||||
Op_LesserEqual,
|
||||
Op_GreaterEqual,
|
||||
Op_Subscript,
|
||||
Op_Indirection,
|
||||
Op_AddressOf,
|
||||
Op_MemberOfPointer,
|
||||
Op_PtrToMemOfPtr,
|
||||
Op_FunctionCall,
|
||||
Op_Comma,
|
||||
Op_New,
|
||||
Op_NewArray,
|
||||
Op_Delete,
|
||||
Op_DeleteArray,
|
||||
Op_NumOps,
|
||||
Op_UnderlyingType = 0xffffffffu
|
||||
};
|
||||
|
||||
inline StrC to_str( Type op )
|
||||
inline StrC operator_to_str( Operator op )
|
||||
{
|
||||
local_persist StrC lookup[] {
|
||||
local_persist StrC lookup[47] = {
|
||||
{ sizeof( "INVALID" ), "INVALID" },
|
||||
{ sizeof( "=" ), "=" },
|
||||
{ sizeof( "+=" ), "+=" },
|
||||
@@ -113,6 +112,7 @@ namespace EOperator
|
||||
return lookup[op];
|
||||
}
|
||||
|
||||
} // namespace EOperator
|
||||
|
||||
using OperatorT = EOperator::Type;
|
||||
forceinline StrC to_str( Operator op )
|
||||
{
|
||||
return operator_to_str( op );
|
||||
}
|
||||
|
||||
@@ -5,47 +5,41 @@
|
||||
|
||||
// This file was generated automatially by gencpp's bootstrap.cpp (See: https://github.com/Ed94/gencpp)
|
||||
|
||||
namespace ESpecifier
|
||||
enum Specifier : u32
|
||||
{
|
||||
enum Type : u32
|
||||
{
|
||||
Invalid,
|
||||
Consteval,
|
||||
Constexpr,
|
||||
Constinit,
|
||||
Explicit,
|
||||
External_Linkage,
|
||||
ForceInline,
|
||||
Global,
|
||||
Inline,
|
||||
Internal_Linkage,
|
||||
Local_Persist,
|
||||
Mutable,
|
||||
NeverInline,
|
||||
Ptr,
|
||||
Ref,
|
||||
Register,
|
||||
RValue,
|
||||
Static,
|
||||
Thread_Local,
|
||||
Virtual,
|
||||
Const,
|
||||
Final,
|
||||
NoExceptions,
|
||||
Override,
|
||||
Pure,
|
||||
Volatile,
|
||||
NumSpecifiers
|
||||
Spec_Invalid,
|
||||
Spec_Consteval,
|
||||
Spec_Constexpr,
|
||||
Spec_Constinit,
|
||||
Spec_Explicit,
|
||||
Spec_External_Linkage,
|
||||
Spec_ForceInline,
|
||||
Spec_Global,
|
||||
Spec_Inline,
|
||||
Spec_Internal_Linkage,
|
||||
Spec_Local_Persist,
|
||||
Spec_Mutable,
|
||||
Spec_NeverInline,
|
||||
Spec_Ptr,
|
||||
Spec_Ref,
|
||||
Spec_Register,
|
||||
Spec_RValue,
|
||||
Spec_Static,
|
||||
Spec_Thread_Local,
|
||||
Spec_Virtual,
|
||||
Spec_Const,
|
||||
Spec_Final,
|
||||
Spec_NoExceptions,
|
||||
Spec_Override,
|
||||
Spec_Pure,
|
||||
Spec_Volatile,
|
||||
Spec_NumSpecifiers,
|
||||
Spec_UnderlyingType = 0xffffffffu
|
||||
};
|
||||
|
||||
inline bool is_trailing( Type specifier )
|
||||
inline StrC spec_to_str( Specifier type )
|
||||
{
|
||||
return specifier > Virtual;
|
||||
}
|
||||
|
||||
inline StrC to_str( Type type )
|
||||
{
|
||||
local_persist StrC lookup[] {
|
||||
local_persist StrC lookup[26] = {
|
||||
{ sizeof( "INVALID" ), "INVALID" },
|
||||
{ sizeof( "consteval" ), "consteval" },
|
||||
{ sizeof( "constexpr" ), "constexpr" },
|
||||
@@ -76,23 +70,39 @@ namespace ESpecifier
|
||||
return lookup[type];
|
||||
}
|
||||
|
||||
inline Type to_type( StrC str )
|
||||
inline bool spec_is_trailing( Specifier specifier )
|
||||
{
|
||||
local_persist u32 keymap[NumSpecifiers];
|
||||
do_once_start for ( u32 index = 0; index < NumSpecifiers; index++ )
|
||||
return specifier > Spec_Virtual;
|
||||
}
|
||||
|
||||
inline Specifier strc_to_specifier( StrC str )
|
||||
{
|
||||
StrC enum_str = to_str( (Type)index );
|
||||
local_persist u32 keymap[Spec_NumSpecifiers];
|
||||
do_once_start for ( u32 index = 0; index < Spec_NumSpecifiers; index++ )
|
||||
{
|
||||
StrC enum_str = spec_to_str( (Specifier)index );
|
||||
keymap[index] = crc32( enum_str.Ptr, enum_str.Len - 1 );
|
||||
}
|
||||
do_once_end u32 hash = crc32( str.Ptr, str.Len );
|
||||
for ( u32 index = 0; index < NumSpecifiers; index++ )
|
||||
for ( u32 index = 0; index < Spec_NumSpecifiers; index++ )
|
||||
{
|
||||
if ( keymap[index] == hash )
|
||||
return (Type)index;
|
||||
return (Specifier)index;
|
||||
}
|
||||
return Invalid;
|
||||
return Spec_Invalid;
|
||||
}
|
||||
|
||||
} // namespace ESpecifier
|
||||
forceinline StrC to_str( Specifier spec )
|
||||
{
|
||||
return spec_to_str( spec );
|
||||
}
|
||||
|
||||
using SpecifierT = ESpecifier::Type;
|
||||
forceinline Specifier to_type( StrC str )
|
||||
{
|
||||
return strc_to_specifier( str );
|
||||
}
|
||||
|
||||
forceinline bool is_trailing( Specifier specifier )
|
||||
{
|
||||
return spec_is_trailing( specifier );
|
||||
}
|
||||
|
||||
+112
-118
@@ -5,117 +5,115 @@
|
||||
|
||||
// This file was generated automatially by gencpp's bootstrap.cpp (See: https://github.com/Ed94/gencpp)
|
||||
|
||||
namespace parser
|
||||
{
|
||||
namespace ETokType
|
||||
{
|
||||
#define GEN_DEFINE_ATTRIBUTE_TOKENS Entry( Attribute_API_Export, "GEN_API_Export_Code" ) Entry( Attribute_API_Import, "GEN_API_Import_Code" )
|
||||
GEN_NS_PARSER_BEGIN
|
||||
|
||||
enum Type : u32
|
||||
#define GEN_DEFINE_ATTRIBUTE_TOKENS Entry( Tok_Attribute_API_Export, "GEN_API_Export_Code" ) Entry( Tok_Attribute_API_Import, "GEN_API_Import_Code" )
|
||||
|
||||
enum TokType : u32
|
||||
{
|
||||
Invalid,
|
||||
Access_Private,
|
||||
Access_Protected,
|
||||
Access_Public,
|
||||
Access_MemberSymbol,
|
||||
Access_StaticSymbol,
|
||||
Ampersand,
|
||||
Ampersand_DBL,
|
||||
Assign_Classifer,
|
||||
Attribute_Open,
|
||||
Attribute_Close,
|
||||
BraceCurly_Open,
|
||||
BraceCurly_Close,
|
||||
BraceSquare_Open,
|
||||
BraceSquare_Close,
|
||||
Capture_Start,
|
||||
Capture_End,
|
||||
Comment,
|
||||
Comment_End,
|
||||
Comment_Start,
|
||||
Char,
|
||||
Comma,
|
||||
Decl_Class,
|
||||
Decl_GNU_Attribute,
|
||||
Decl_MSVC_Attribute,
|
||||
Decl_Enum,
|
||||
Decl_Extern_Linkage,
|
||||
Decl_Friend,
|
||||
Decl_Module,
|
||||
Decl_Namespace,
|
||||
Decl_Operator,
|
||||
Decl_Struct,
|
||||
Decl_Template,
|
||||
Decl_Typedef,
|
||||
Decl_Using,
|
||||
Decl_Union,
|
||||
Identifier,
|
||||
Module_Import,
|
||||
Module_Export,
|
||||
NewLine,
|
||||
Number,
|
||||
Operator,
|
||||
Preprocess_Hash,
|
||||
Preprocess_Define,
|
||||
Preprocess_If,
|
||||
Preprocess_IfDef,
|
||||
Preprocess_IfNotDef,
|
||||
Preprocess_ElIf,
|
||||
Preprocess_Else,
|
||||
Preprocess_EndIf,
|
||||
Preprocess_Include,
|
||||
Preprocess_Pragma,
|
||||
Preprocess_Content,
|
||||
Preprocess_Macro,
|
||||
Preprocess_Unsupported,
|
||||
Spec_Alignas,
|
||||
Spec_Const,
|
||||
Spec_Consteval,
|
||||
Spec_Constexpr,
|
||||
Spec_Constinit,
|
||||
Spec_Explicit,
|
||||
Spec_Extern,
|
||||
Spec_Final,
|
||||
Spec_ForceInline,
|
||||
Spec_Global,
|
||||
Spec_Inline,
|
||||
Spec_Internal_Linkage,
|
||||
Spec_LocalPersist,
|
||||
Spec_Mutable,
|
||||
Spec_NeverInline,
|
||||
Spec_Override,
|
||||
Spec_Static,
|
||||
Spec_ThreadLocal,
|
||||
Spec_Volatile,
|
||||
Spec_Virtual,
|
||||
Star,
|
||||
Statement_End,
|
||||
StaticAssert,
|
||||
String,
|
||||
Type_Typename,
|
||||
Type_Unsigned,
|
||||
Type_Signed,
|
||||
Type_Short,
|
||||
Type_Long,
|
||||
Type_bool,
|
||||
Type_char,
|
||||
Type_int,
|
||||
Type_double,
|
||||
Type_MS_int8,
|
||||
Type_MS_int16,
|
||||
Type_MS_int32,
|
||||
Type_MS_int64,
|
||||
Type_MS_W64,
|
||||
Varadic_Argument,
|
||||
__Attributes_Start,
|
||||
Attribute_API_Export,
|
||||
Attribute_API_Import,
|
||||
NumTokens
|
||||
Tok_Invalid,
|
||||
Tok_Access_Private,
|
||||
Tok_Access_Protected,
|
||||
Tok_Access_Public,
|
||||
Tok_Access_MemberSymbol,
|
||||
Tok_Access_StaticSymbol,
|
||||
Tok_Ampersand,
|
||||
Tok_Ampersand_DBL,
|
||||
Tok_Assign_Classifer,
|
||||
Tok_Attribute_Open,
|
||||
Tok_Attribute_Close,
|
||||
Tok_BraceCurly_Open,
|
||||
Tok_BraceCurly_Close,
|
||||
Tok_BraceSquare_Open,
|
||||
Tok_BraceSquare_Close,
|
||||
Tok_Capture_Start,
|
||||
Tok_Capture_End,
|
||||
Tok_Comment,
|
||||
Tok_Comment_End,
|
||||
Tok_Comment_Start,
|
||||
Tok_Char,
|
||||
Tok_Comma,
|
||||
Tok_Decl_Class,
|
||||
Tok_Decl_GNU_Attribute,
|
||||
Tok_Decl_MSVC_Attribute,
|
||||
Tok_Decl_Enum,
|
||||
Tok_Decl_Extern_Linkage,
|
||||
Tok_Decl_Friend,
|
||||
Tok_Decl_Module,
|
||||
Tok_Decl_Namespace,
|
||||
Tok_Decl_Operator,
|
||||
Tok_Decl_Struct,
|
||||
Tok_Decl_Template,
|
||||
Tok_Decl_Typedef,
|
||||
Tok_Decl_Using,
|
||||
Tok_Decl_Union,
|
||||
Tok_Identifier,
|
||||
Tok_Module_Import,
|
||||
Tok_Module_Export,
|
||||
Tok_NewLine,
|
||||
Tok_Number,
|
||||
Tok_Operator,
|
||||
Tok_Preprocess_Hash,
|
||||
Tok_Preprocess_Define,
|
||||
Tok_Preprocess_If,
|
||||
Tok_Preprocess_IfDef,
|
||||
Tok_Preprocess_IfNotDef,
|
||||
Tok_Preprocess_ElIf,
|
||||
Tok_Preprocess_Else,
|
||||
Tok_Preprocess_EndIf,
|
||||
Tok_Preprocess_Include,
|
||||
Tok_Preprocess_Pragma,
|
||||
Tok_Preprocess_Content,
|
||||
Tok_Preprocess_Macro,
|
||||
Tok_Preprocess_Unsupported,
|
||||
Tok_Spec_Alignas,
|
||||
Tok_Spec_Const,
|
||||
Tok_Spec_Consteval,
|
||||
Tok_Spec_Constexpr,
|
||||
Tok_Spec_Constinit,
|
||||
Tok_Spec_Explicit,
|
||||
Tok_Spec_Extern,
|
||||
Tok_Spec_Final,
|
||||
Tok_Spec_ForceInline,
|
||||
Tok_Spec_Global,
|
||||
Tok_Spec_Inline,
|
||||
Tok_Spec_Internal_Linkage,
|
||||
Tok_Spec_LocalPersist,
|
||||
Tok_Spec_Mutable,
|
||||
Tok_Spec_NeverInline,
|
||||
Tok_Spec_Override,
|
||||
Tok_Spec_Static,
|
||||
Tok_Spec_ThreadLocal,
|
||||
Tok_Spec_Volatile,
|
||||
Tok_Spec_Virtual,
|
||||
Tok_Star,
|
||||
Tok_Statement_End,
|
||||
Tok_StaticAssert,
|
||||
Tok_String,
|
||||
Tok_Type_Typename,
|
||||
Tok_Type_Unsigned,
|
||||
Tok_Type_Signed,
|
||||
Tok_Type_Short,
|
||||
Tok_Type_Long,
|
||||
Tok_Type_bool,
|
||||
Tok_Type_char,
|
||||
Tok_Type_int,
|
||||
Tok_Type_double,
|
||||
Tok_Type_MS_int8,
|
||||
Tok_Type_MS_int16,
|
||||
Tok_Type_MS_int32,
|
||||
Tok_Type_MS_int64,
|
||||
Tok_Type_MS_W64,
|
||||
Tok_Varadic_Argument,
|
||||
Tok___Attributes_Start,
|
||||
Tok_Attribute_API_Export,
|
||||
Tok_Attribute_API_Import,
|
||||
Tok_NumTokens
|
||||
};
|
||||
|
||||
inline StrC to_str( Type type )
|
||||
inline StrC toktype_to_str( TokType type )
|
||||
{
|
||||
local_persist StrC lookup[] {
|
||||
local_persist StrC lookup[] = {
|
||||
{ sizeof( "__invalid__" ), "__invalid__" },
|
||||
{ sizeof( "private" ), "private" },
|
||||
{ sizeof( "protected" ), "protected" },
|
||||
@@ -217,25 +215,21 @@ namespace parser
|
||||
return lookup[type];
|
||||
}
|
||||
|
||||
inline Type to_type( StrC str )
|
||||
inline TokType strc_to_toktype( StrC str )
|
||||
{
|
||||
local_persist u32 keymap[NumTokens];
|
||||
do_once_start for ( u32 index = 0; index < NumTokens; index++ )
|
||||
local_persist u32 keymap[Tok_NumTokens];
|
||||
do_once_start for ( u32 index = 0; index < Tok_NumTokens; index++ )
|
||||
{
|
||||
StrC enum_str = to_str( (Type)index );
|
||||
StrC enum_str = toktype_to_str( (TokType)index );
|
||||
keymap[index] = crc32( enum_str.Ptr, enum_str.Len - 1 );
|
||||
}
|
||||
do_once_end u32 hash = crc32( str.Ptr, str.Len );
|
||||
for ( u32 index = 0; index < NumTokens; index++ )
|
||||
for ( u32 index = 0; index < Tok_NumTokens; index++ )
|
||||
{
|
||||
if ( keymap[index] == hash )
|
||||
return (Type)index;
|
||||
return (TokType)index;
|
||||
}
|
||||
return Invalid;
|
||||
return Tok_Invalid;
|
||||
}
|
||||
|
||||
} // namespace ETokType
|
||||
|
||||
using TokType = ETokType::Type;
|
||||
|
||||
} // namespace parser
|
||||
GEN_NS_PARSER_END
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
# define GEN_MAX_UNTYPED_STR_LENGTH megabytes(1)
|
||||
#endif
|
||||
#ifndef GEN_TOKEN_FMT_TOKEN_MAP_MEM_SIZE
|
||||
# define GEN_TOKEN_FMT_TOKEN_MAP_MEM_SIZE kilobytes(4)
|
||||
# define GEN_TOKEN_FMT_TOKEN_MAP_MEM_SIZE kilobytes(8)
|
||||
#endif
|
||||
#ifndef GEN_LEX_ALLOCATOR_SIZE
|
||||
# define GEN_LEX_ALLOCATOR_SIZE megabytes(4)
|
||||
@@ -97,76 +97,52 @@ extern CodeSpecifiers spec_thread_local;
|
||||
extern CodeSpecifiers spec_virtual;
|
||||
extern CodeSpecifiers spec_volatile;
|
||||
|
||||
extern CodeType t_empty; // Used with varaidc parameters. (Exposing just in case its useful for another circumstance)
|
||||
extern CodeType t_auto;
|
||||
extern CodeType t_void;
|
||||
extern CodeType t_int;
|
||||
extern CodeType t_bool;
|
||||
extern CodeType t_char;
|
||||
extern CodeType t_wchar_t;
|
||||
extern CodeType t_class;
|
||||
extern CodeType t_typename;
|
||||
extern CodeTypename t_empty; // Used with varaidc parameters. (Exposing just in case its useful for another circumstance)
|
||||
extern CodeTypename t_auto;
|
||||
extern CodeTypename t_void;
|
||||
extern CodeTypename t_int;
|
||||
extern CodeTypename t_bool;
|
||||
extern CodeTypename t_char;
|
||||
extern CodeTypename t_wchar_t;
|
||||
extern CodeTypename t_class;
|
||||
extern CodeTypename t_typename;
|
||||
|
||||
#ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS
|
||||
// Predefined typename codes. Are set to readonly and are setup during gen::init()
|
||||
|
||||
extern CodeType t_b32;
|
||||
extern CodeTypename t_b32;
|
||||
|
||||
extern CodeType t_s8;
|
||||
extern CodeType t_s16;
|
||||
extern CodeType t_s32;
|
||||
extern CodeType t_s64;
|
||||
extern CodeTypename t_s8;
|
||||
extern CodeTypename t_s16;
|
||||
extern CodeTypename t_s32;
|
||||
extern CodeTypename t_s64;
|
||||
|
||||
extern CodeType t_u8;
|
||||
extern CodeType t_u16;
|
||||
extern CodeType t_u32;
|
||||
extern CodeType t_u64;
|
||||
extern CodeTypename t_u8;
|
||||
extern CodeTypename t_u16;
|
||||
extern CodeTypename t_u32;
|
||||
extern CodeTypename t_u64;
|
||||
|
||||
extern CodeType t_ssize;
|
||||
extern CodeType t_usize;
|
||||
extern CodeTypename t_ssize;
|
||||
extern CodeTypename t_usize;
|
||||
|
||||
extern CodeType t_f32;
|
||||
extern CodeType t_f64;
|
||||
extern CodeTypename t_f32;
|
||||
extern CodeTypename t_f64;
|
||||
#endif
|
||||
|
||||
#pragma endregion Constants
|
||||
|
||||
#pragma region Macros
|
||||
|
||||
# define gen_main main
|
||||
|
||||
# define __ NoCode
|
||||
|
||||
// Convienence for defining any name used with the gen api.
|
||||
// Lets you provide the length and string literal to the functions without the need for the DSL.
|
||||
# define name( Id_ ) { sizeof(stringize( Id_ )) - 1, stringize(Id_) }
|
||||
|
||||
// Same as name just used to indicate intention of literal for code instead of names.
|
||||
# define code( ... ) { sizeof(stringize(__VA_ARGS__)) - 1, stringize( __VA_ARGS__ ) }
|
||||
|
||||
# define args( ... ) num_args( __VA_ARGS__ ), __VA_ARGS__
|
||||
|
||||
# define code_str( ... ) GEN_NS untyped_str( code( __VA_ARGS__ ) )
|
||||
# define code_fmt( ... ) GEN_NS untyped_str( token_fmt( __VA_ARGS__ ) )
|
||||
|
||||
// Takes a format string (char const*) and a list of tokens (StrC) and returns a StrC of the formatted string.
|
||||
# define token_fmt( ... ) GEN_NS token_fmt_impl( (num_args( __VA_ARGS__ ) + 1) / 2, __VA_ARGS__ )
|
||||
|
||||
#pragma endregion Macros
|
||||
|
||||
// Used by the lexer to persistently treat all these identifiers as preprocessor defines.
|
||||
// Populate with strings via gen::get_cached_string.
|
||||
// Functional defines must have format: id( ;at minimum to indicate that the define is only valid with arguments.
|
||||
extern Array< StringCached > PreprocessorDefines;
|
||||
extern Array(StringCached) PreprocessorDefines;
|
||||
|
||||
#ifdef GEN_EXPOSE_BACKEND
|
||||
|
||||
// Global allocator used for data with process lifetime.
|
||||
extern AllocatorInfo GlobalAllocator;
|
||||
extern Array< Arena > Global_AllocatorBuckets;
|
||||
extern Array(Arena) Global_AllocatorBuckets;
|
||||
|
||||
extern Array< Pool > CodePools;
|
||||
extern Array< Arena > StringArenas;
|
||||
extern Array(Pool) CodePools;
|
||||
extern Array(Arena) StringArenas;
|
||||
|
||||
extern StringTable StringCache;
|
||||
|
||||
@@ -178,5 +154,4 @@ extern Array< StringCached > PreprocessorDefines;
|
||||
extern AllocatorInfo Allocator_StringArena;
|
||||
extern AllocatorInfo Allocator_StringTable;
|
||||
extern AllocatorInfo Allocator_TypeTable;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,7 +6,20 @@
|
||||
See Readme.md for more information from the project repository.
|
||||
|
||||
Public Address:
|
||||
https://github.com/Ed94/gencpp
|
||||
https://github.com/Ed94/gencpp --------------------------------------------------------------.
|
||||
| _____ _____ _ _ |
|
||||
| / ____) / ____} | | | |
|
||||
| | / ___ ___ _ __ ___ _ __ _ __ | {___ | |__ _ _, __ _, ___ __| | |
|
||||
| | |{_ |/ _ \ '_ \ / __} '_ l| '_ l `\___ \| __/ _` |/ _` |/ _ \/ _` | |
|
||||
| | l__j | ___/ | | | {__; |+l } |+l | ____) | l| (_| | {_| | ___/ (_| | |
|
||||
| \_____|\___}_l |_|\___} ,__/| ,__/ (_____/ \__\__/_|\__, |\___}\__,_l |
|
||||
| | | | | __} | |
|
||||
| l_l l_l {___/ |
|
||||
! ----------------------------------------------------------------------- VERSION: v0.20-Alpha |
|
||||
! ============================================================================================ |
|
||||
! WARNING: THIS IS AN ALPHA VERSION OF THE LIBRARY, USE AT YOUR OWN DISCRETION |
|
||||
! NEVER DO CODE GENERATION WITHOUT AT LEAST HAVING CONTENT IN A CODEBASE UNDER VERSION CONTROL |
|
||||
! ============================================================================================ /
|
||||
*/
|
||||
#if ! defined(GEN_DONT_ENFORCE_GEN_TIME_GUARD) && ! defined(GEN_TIME)
|
||||
# error Gen.hpp : GEN_TIME not defined
|
||||
@@ -17,15 +30,3 @@
|
||||
#ifndef GEN_ROLL_OWN_DEPENDENCIES
|
||||
# include "gen.dep.hpp"
|
||||
#endif
|
||||
|
||||
#ifndef GEN_NS_BEGIN
|
||||
# ifdef GEN_DONT_USE_NAMESPACE
|
||||
# define GEN_NS
|
||||
# define GEN_NS_BEGIN
|
||||
# define GEN_NS_END
|
||||
# else
|
||||
# define GEN_NS gen::
|
||||
# define GEN_NS_BEGIN namespace gen {
|
||||
# define GEN_NS_END }
|
||||
# endif
|
||||
#endif
|
||||
|
||||
+287
-81
@@ -3,102 +3,193 @@
|
||||
#include "interface.hpp"
|
||||
#endif
|
||||
|
||||
#pragma region Code
|
||||
inline
|
||||
void AST::append( AST* other )
|
||||
void code_append( Code self, Code other )
|
||||
{
|
||||
if ( other->Parent )
|
||||
other = other->duplicate();
|
||||
GEN_ASSERT(self);
|
||||
GEN_ASSERT(other);
|
||||
GEN_ASSERT_MSG(self != other, "Attempted to recursively append Code AST to itself.");
|
||||
|
||||
other->Parent = this;
|
||||
if ( other->Parent != nullptr )
|
||||
other = code_duplicate(other);
|
||||
|
||||
if ( Front == nullptr )
|
||||
other->Parent = self;
|
||||
|
||||
if ( self->Front == nullptr )
|
||||
{
|
||||
Front = other;
|
||||
Back = other;
|
||||
self->Front = other;
|
||||
self->Back = other;
|
||||
|
||||
NumEntries++;
|
||||
self->NumEntries++;
|
||||
return;
|
||||
}
|
||||
|
||||
AST*
|
||||
Current = Back;
|
||||
Code
|
||||
Current = self->Back;
|
||||
Current->Next = other;
|
||||
other->Prev = Current;
|
||||
Back = other;
|
||||
NumEntries++;
|
||||
self->Back = other;
|
||||
self->NumEntries++;
|
||||
}
|
||||
|
||||
inline
|
||||
Code& AST::entry( u32 idx )
|
||||
bool code_is_body(Code self)
|
||||
{
|
||||
AST** current = & Front;
|
||||
GEN_ASSERT(self);
|
||||
switch (self->Type)
|
||||
{
|
||||
case CT_Enum_Body:
|
||||
case CT_Class_Body:
|
||||
case CT_Union_Body:
|
||||
case CT_Export_Body:
|
||||
case CT_Global_Body:
|
||||
case CT_Struct_Body:
|
||||
case CT_Function_Body:
|
||||
case CT_Namespace_Body:
|
||||
case CT_Extern_Linkage_Body:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
inline
|
||||
Code* code_entry( Code self, u32 idx )
|
||||
{
|
||||
GEN_ASSERT(self != nullptr);
|
||||
Code* current = & self->Front;
|
||||
while ( idx >= 0 && current != nullptr )
|
||||
{
|
||||
if ( idx == 0 )
|
||||
return * rcast( Code*, current);
|
||||
return rcast( Code*, current);
|
||||
|
||||
current = & ( * current )->Next;
|
||||
idx--;
|
||||
}
|
||||
|
||||
return * rcast( Code*, current);
|
||||
return rcast( Code*, current);
|
||||
}
|
||||
|
||||
inline
|
||||
bool AST::has_entries()
|
||||
forceinline
|
||||
bool code_is_valid(Code self)
|
||||
{
|
||||
return NumEntries > 0;
|
||||
GEN_ASSERT(self);
|
||||
return self != nullptr && self->Type != CT_Invalid;
|
||||
}
|
||||
|
||||
inline
|
||||
char const* AST::type_str()
|
||||
forceinline
|
||||
bool code_has_entries(AST* self)
|
||||
{
|
||||
return ECode::to_str( Type );
|
||||
GEN_ASSERT(self);
|
||||
return self->NumEntries > 0;
|
||||
}
|
||||
|
||||
inline
|
||||
AST::operator Code()
|
||||
forceinline
|
||||
void code_set_global(Code self)
|
||||
{
|
||||
return { this };
|
||||
if ( self == nullptr )
|
||||
{
|
||||
log_failure("Code::set_global: Cannot set code as global, AST is null!");
|
||||
return;
|
||||
}
|
||||
|
||||
inline
|
||||
self->Parent = Code_Global;
|
||||
}
|
||||
#if GEN_COMPILER_CPP
|
||||
forceinline
|
||||
Code& Code::operator ++()
|
||||
{
|
||||
if ( ast )
|
||||
ast = ast->Next;
|
||||
ast = ast->Next.ast;
|
||||
|
||||
return * this;
|
||||
}
|
||||
|
||||
inline
|
||||
void CodeClass::add_interface( CodeType type )
|
||||
#endif
|
||||
forceinline
|
||||
StrC code_type_str(Code self)
|
||||
{
|
||||
CodeType possible_slot = ast->ParentType;
|
||||
if ( possible_slot.ast )
|
||||
GEN_ASSERT(self != nullptr);
|
||||
return codetype_to_str( self->Type );
|
||||
}
|
||||
#pragma endregion Code
|
||||
|
||||
#pragma region CodeBody
|
||||
inline
|
||||
void body_append( CodeBody self, Code other )
|
||||
{
|
||||
GEN_ASSERT(self);
|
||||
GEN_ASSERT(other);
|
||||
|
||||
if (code_is_body(other)) {
|
||||
body_append_body( self, cast(CodeBody, other) );
|
||||
return;
|
||||
}
|
||||
|
||||
code_append( cast(Code, self), other );
|
||||
}
|
||||
inline
|
||||
void body_append_body( CodeBody self, CodeBody body )
|
||||
{
|
||||
GEN_ASSERT(self);
|
||||
GEN_ASSERT(body);
|
||||
GEN_ASSERT_MSG(self != body, "Attempted to append body to itself.");
|
||||
|
||||
for ( Code entry = begin_CodeBody(body); entry != end_CodeBody(body); entry = next_CodeBody(body, entry) ) {
|
||||
body_append( self, entry );
|
||||
}
|
||||
}
|
||||
inline
|
||||
Code begin_CodeBody( CodeBody body) {
|
||||
GEN_ASSERT(body);
|
||||
if ( body != nullptr )
|
||||
return body->Front;
|
||||
|
||||
return NullCode;
|
||||
}
|
||||
forceinline
|
||||
Code end_CodeBody(CodeBody body ){
|
||||
GEN_ASSERT(body);
|
||||
return body->Back->Next;
|
||||
}
|
||||
inline
|
||||
Code next_CodeBody(CodeBody body, Code entry) {
|
||||
GEN_ASSERT(body);
|
||||
GEN_ASSERT(entry);
|
||||
return entry->Next;
|
||||
}
|
||||
#pragma endregion CodeBody
|
||||
|
||||
#pragma region CodeClass
|
||||
inline
|
||||
void class_add_interface( CodeClass self, CodeTypename type )
|
||||
{
|
||||
GEN_ASSERT(self);
|
||||
GEN_ASSERT(type);
|
||||
CodeTypename possible_slot = self->ParentType;
|
||||
if ( possible_slot != nullptr )
|
||||
{
|
||||
// Were adding an interface to parent type, so we need to make sure the parent type is public.
|
||||
ast->ParentAccess = AccessSpec::Public;
|
||||
self->ParentAccess = AccessSpec_Public;
|
||||
// If your planning on adding a proper parent,
|
||||
// then you'll need to move this over to ParentType->next and update ParentAccess accordingly.
|
||||
}
|
||||
|
||||
while ( possible_slot.ast != nullptr )
|
||||
while ( possible_slot != nullptr )
|
||||
{
|
||||
possible_slot.ast = (AST_Type*) possible_slot->Next.ast;
|
||||
possible_slot = cast(CodeTypename, possible_slot->Next);
|
||||
}
|
||||
|
||||
possible_slot.ast = type.ast;
|
||||
possible_slot = type;
|
||||
}
|
||||
#pragma endregion CodeClass
|
||||
|
||||
#pragma region CodeParam
|
||||
inline
|
||||
void CodeParam::append( CodeParam other )
|
||||
void params_append( CodeParam appendee, CodeParam other )
|
||||
{
|
||||
AST* self = (AST*) ast;
|
||||
AST* entry = (AST*) other.ast;
|
||||
GEN_ASSERT(appendee);
|
||||
GEN_ASSERT(other);
|
||||
GEN_ASSERT_MSG(appendee != other, "Attempted to append parameter to itself.");
|
||||
Code self = cast(Code, appendee);
|
||||
Code entry = cast(Code, other);
|
||||
|
||||
if ( entry->Parent )
|
||||
entry = entry->duplicate();
|
||||
if ( entry->Parent != nullptr )
|
||||
entry = code_duplicate( entry );
|
||||
|
||||
entry->Parent = self;
|
||||
|
||||
@@ -114,76 +205,189 @@ void CodeParam::append( CodeParam other )
|
||||
self->Last = entry;
|
||||
self->NumEntries++;
|
||||
}
|
||||
|
||||
inline
|
||||
CodeParam CodeParam::get( s32 idx )
|
||||
CodeParam params_get(CodeParam self, s32 idx )
|
||||
{
|
||||
CodeParam param = *this;
|
||||
GEN_ASSERT(self);
|
||||
CodeParam param = self;
|
||||
do
|
||||
{
|
||||
if ( ! ++ param )
|
||||
return { nullptr };
|
||||
if ( ++ param != nullptr )
|
||||
return NullCode;
|
||||
|
||||
param = { (AST_Param*) param.raw()->Next };
|
||||
param = cast(CodeParam, cast(Code, param)->Next);
|
||||
}
|
||||
while ( --idx );
|
||||
|
||||
return param;
|
||||
}
|
||||
|
||||
inline
|
||||
bool CodeParam::has_entries()
|
||||
forceinline
|
||||
bool params_has_entries(CodeParam self)
|
||||
{
|
||||
return ast->NumEntries > 0;
|
||||
GEN_ASSERT(self);
|
||||
return self->NumEntries > 0;
|
||||
}
|
||||
|
||||
inline
|
||||
#if GEN_COMPILER_CPP
|
||||
forceinline
|
||||
CodeParam& CodeParam::operator ++()
|
||||
{
|
||||
ast = ast->Next.ast;
|
||||
* this = ast->Next;
|
||||
return * this;
|
||||
}
|
||||
|
||||
inline
|
||||
void CodeStruct::add_interface( CodeType type )
|
||||
#endif
|
||||
forceinline
|
||||
CodeParam begin_CodeParam(CodeParam params)
|
||||
{
|
||||
CodeType possible_slot = ast->ParentType;
|
||||
if ( possible_slot.ast )
|
||||
if ( params != nullptr )
|
||||
return params;
|
||||
|
||||
return NullCode;
|
||||
}
|
||||
forceinline
|
||||
CodeParam end_CodeParam(CodeParam params)
|
||||
{
|
||||
// return { (AST_Param*) rcast( AST*, ast)->Last };
|
||||
return NullCode;
|
||||
}
|
||||
forceinline
|
||||
CodeParam next_CodeParam(CodeParam params, CodeParam param_iter)
|
||||
{
|
||||
GEN_ASSERT(param_iter);
|
||||
return param_iter->Next;
|
||||
}
|
||||
#pragma endregion CodeParam
|
||||
|
||||
#pragma region CodeSpecifiers
|
||||
inline
|
||||
bool specifiers_append(CodeSpecifiers self, Specifier spec )
|
||||
{
|
||||
if ( self == nullptr )
|
||||
{
|
||||
log_failure("CodeSpecifiers: Attempted to append to a null specifiers AST!");
|
||||
return false;
|
||||
}
|
||||
if ( self->NumEntries == AST_ArrSpecs_Cap )
|
||||
{
|
||||
log_failure("CodeSpecifiers: Attempted to append over %d specifiers to a specifiers AST!", AST_ArrSpecs_Cap );
|
||||
return false;
|
||||
}
|
||||
|
||||
self->ArrSpecs[ self->NumEntries ] = spec;
|
||||
self->NumEntries++;
|
||||
return true;
|
||||
}
|
||||
inline
|
||||
s32 specifiers_has(CodeSpecifiers self, Specifier spec)
|
||||
{
|
||||
GEN_ASSERT(self != nullptr);
|
||||
for ( s32 idx = 0; idx < self->NumEntries; idx++ ) {
|
||||
if ( self->ArrSpecs[ idx ] == spec )
|
||||
return idx;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
inline
|
||||
s32 specifiers_remove( CodeSpecifiers self, Specifier to_remove )
|
||||
{
|
||||
if ( self == nullptr )
|
||||
{
|
||||
log_failure("CodeSpecifiers: Attempted to append to a null specifiers AST!");
|
||||
return -1;
|
||||
}
|
||||
if ( self->NumEntries == AST_ArrSpecs_Cap )
|
||||
{
|
||||
log_failure("CodeSpecifiers: Attempted to append over %d specifiers to a specifiers AST!", AST_ArrSpecs_Cap );
|
||||
return -1;
|
||||
}
|
||||
|
||||
s32 result = -1;
|
||||
|
||||
s32 curr = 0;
|
||||
s32 next = 0;
|
||||
for(; next < self->NumEntries; ++ curr, ++ next)
|
||||
{
|
||||
Specifier spec = self->ArrSpecs[next];
|
||||
if (spec == to_remove)
|
||||
{
|
||||
result = next;
|
||||
|
||||
next ++;
|
||||
if (next >= self->NumEntries)
|
||||
break;
|
||||
|
||||
spec = self->ArrSpecs[next];
|
||||
}
|
||||
|
||||
self->ArrSpecs[ curr ] = spec;
|
||||
}
|
||||
|
||||
if (result > -1) {
|
||||
self->NumEntries --;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
forceinline
|
||||
Specifier* begin_CodeSpecifiers(CodeSpecifiers self)
|
||||
{
|
||||
if ( self != nullptr )
|
||||
return & self->ArrSpecs[0];
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
forceinline
|
||||
Specifier* end_CodeSpecifiers(CodeSpecifiers self)
|
||||
{
|
||||
return self->ArrSpecs + self->NumEntries;
|
||||
}
|
||||
forceinline
|
||||
Specifier* next_CodeSpecifiers(CodeSpecifiers self, Specifier* spec_iter)
|
||||
{
|
||||
return spec_iter + 1;
|
||||
}
|
||||
#pragma endregion CodeSpecifiers
|
||||
|
||||
#pragma region CodeStruct
|
||||
inline
|
||||
void struct_add_interface(CodeStruct self, CodeTypename type )
|
||||
{
|
||||
CodeTypename possible_slot = self->ParentType;
|
||||
if ( possible_slot != nullptr )
|
||||
{
|
||||
// Were adding an interface to parent type, so we need to make sure the parent type is public.
|
||||
ast->ParentAccess = AccessSpec::Public;
|
||||
self->ParentAccess = AccessSpec_Public;
|
||||
// If your planning on adding a proper parent,
|
||||
// then you'll need to move this over to ParentType->next and update ParentAccess accordingly.
|
||||
}
|
||||
|
||||
while ( possible_slot.ast != nullptr )
|
||||
while ( possible_slot != nullptr )
|
||||
{
|
||||
possible_slot.ast = (AST_Type*) possible_slot->Next.ast;
|
||||
possible_slot = cast(CodeTypename, possible_slot->Next);
|
||||
}
|
||||
|
||||
possible_slot.ast = type.ast;
|
||||
possible_slot = type;
|
||||
}
|
||||
#pragma endregion Code
|
||||
|
||||
#pragma region Interface
|
||||
inline
|
||||
CodeBody def_body( CodeT type )
|
||||
CodeBody def_body( CodeType type )
|
||||
{
|
||||
switch ( type )
|
||||
{
|
||||
using namespace ECode;
|
||||
case Class_Body:
|
||||
case Enum_Body:
|
||||
case Export_Body:
|
||||
case Extern_Linkage:
|
||||
case Function_Body:
|
||||
case Global_Body:
|
||||
case Namespace_Body:
|
||||
case Struct_Body:
|
||||
case Union_Body:
|
||||
case CT_Class_Body:
|
||||
case CT_Enum_Body:
|
||||
case CT_Export_Body:
|
||||
case CT_Extern_Linkage:
|
||||
case CT_Function_Body:
|
||||
case CT_Global_Body:
|
||||
case CT_Namespace_Body:
|
||||
case CT_Struct_Body:
|
||||
case CT_Union_Body:
|
||||
break;
|
||||
|
||||
default:
|
||||
log_failure( "def_body: Invalid type %s", (char const*)ECode::to_str(type) );
|
||||
return (CodeBody)Code::Invalid;
|
||||
log_failure( "def_body: Invalid type %s", codetype_to_str(type).Ptr );
|
||||
return (CodeBody)Code_Invalid;
|
||||
}
|
||||
|
||||
Code
|
||||
@@ -204,5 +408,7 @@ StrC token_fmt_impl( ssize num, ... )
|
||||
ssize result = token_fmt_va(buf, GEN_PRINTF_MAXLEN, num, va);
|
||||
va_end(va);
|
||||
|
||||
return { result, buf };
|
||||
StrC str = { result, buf };
|
||||
return str;
|
||||
}
|
||||
#pragma endregion Interface
|
||||
|
||||
+150
-133
@@ -3,15 +3,15 @@
|
||||
#include "code_serialization.cpp"
|
||||
#endif
|
||||
|
||||
namespace parser {
|
||||
internal void init();
|
||||
internal void deinit();
|
||||
}
|
||||
GEN_NS_PARSER_BEGIN
|
||||
internal void parser_init();
|
||||
internal void parser_deinit();
|
||||
GEN_NS_PARSER_END
|
||||
|
||||
internal
|
||||
void* Global_Allocator_Proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags )
|
||||
{
|
||||
Arena* last = & Global_AllocatorBuckets.back();
|
||||
Arena* last = array_back(Global_AllocatorBuckets);
|
||||
|
||||
switch ( type )
|
||||
{
|
||||
@@ -19,18 +19,18 @@ void* Global_Allocator_Proc( void* allocator_data, AllocType type, ssize size, s
|
||||
{
|
||||
if ( ( last->TotalUsed + size ) > last->TotalSize )
|
||||
{
|
||||
Arena bucket = Arena::init_from_allocator( heap(), Global_BucketSize );
|
||||
Arena bucket = arena_init_from_allocator( heap(), Global_BucketSize );
|
||||
|
||||
if ( bucket.PhysicalStart == nullptr )
|
||||
GEN_FATAL( "Failed to create bucket for Global_AllocatorBuckets");
|
||||
|
||||
if ( ! Global_AllocatorBuckets.append( bucket ) )
|
||||
if ( ! array_append( Global_AllocatorBuckets, bucket ) )
|
||||
GEN_FATAL( "Failed to append bucket to Global_AllocatorBuckets");
|
||||
|
||||
last = & Global_AllocatorBuckets.back();
|
||||
last = array_back(Global_AllocatorBuckets);
|
||||
}
|
||||
|
||||
return alloc_align( * last, size, alignment );
|
||||
return alloc_align( arena_allocator_info(last), size, alignment );
|
||||
}
|
||||
case EAllocation_FREE:
|
||||
{
|
||||
@@ -46,15 +46,15 @@ void* Global_Allocator_Proc( void* allocator_data, AllocType type, ssize size, s
|
||||
{
|
||||
if ( last->TotalUsed + size > last->TotalSize )
|
||||
{
|
||||
Arena bucket = Arena::init_from_allocator( heap(), Global_BucketSize );
|
||||
Arena bucket = arena_init_from_allocator( heap(), Global_BucketSize );
|
||||
|
||||
if ( bucket.PhysicalStart == nullptr )
|
||||
GEN_FATAL( "Failed to create bucket for Global_AllocatorBuckets");
|
||||
|
||||
if ( ! Global_AllocatorBuckets.append( bucket ) )
|
||||
if ( ! array_append( Global_AllocatorBuckets, bucket ) )
|
||||
GEN_FATAL( "Failed to append bucket to Global_AllocatorBuckets");
|
||||
|
||||
last = & Global_AllocatorBuckets.back();
|
||||
last = array_back(Global_AllocatorBuckets);
|
||||
}
|
||||
|
||||
void* result = alloc_align( last->Backing, size, alignment );
|
||||
@@ -74,78 +74,84 @@ void* Global_Allocator_Proc( void* allocator_data, AllocType type, ssize size, s
|
||||
internal
|
||||
void define_constants()
|
||||
{
|
||||
Code::Global = make_code();
|
||||
Code::Global->Name = get_cached_string( txt("Global Code") );
|
||||
Code::Global->Content = Code::Global->Name;
|
||||
Code_Global = make_code();
|
||||
Code_Global->Name = get_cached_string( txt("Global Code") );
|
||||
Code_Global->Content = Code_Global->Name;
|
||||
|
||||
Code::Invalid = make_code();
|
||||
Code::Invalid.set_global();
|
||||
Code_Invalid = make_code();
|
||||
code_set_global(Code_Invalid);
|
||||
|
||||
t_empty = (CodeType) make_code();
|
||||
t_empty->Type = ECode::Typename;
|
||||
t_empty = (CodeTypename) make_code();
|
||||
t_empty->Type = CT_Typename;
|
||||
t_empty->Name = get_cached_string( txt("") );
|
||||
t_empty.set_global();
|
||||
code_set_global(cast(Code, t_empty));
|
||||
|
||||
access_private = make_code();
|
||||
access_private->Type = ECode::Access_Private;
|
||||
access_private->Type = CT_Access_Private;
|
||||
access_private->Name = get_cached_string( txt("private:\n") );
|
||||
access_private.set_global();
|
||||
code_set_global(cast(Code, access_private));
|
||||
|
||||
access_protected = make_code();
|
||||
access_protected->Type = ECode::Access_Protected;
|
||||
access_protected->Type = CT_Access_Protected;
|
||||
access_protected->Name = get_cached_string( txt("protected:\n") );
|
||||
access_protected.set_global();
|
||||
code_set_global(access_protected);
|
||||
|
||||
access_public = make_code();
|
||||
access_public->Type = ECode::Access_Public;
|
||||
access_public->Type = CT_Access_Public;
|
||||
access_public->Name = get_cached_string( txt("public:\n") );
|
||||
access_public.set_global();
|
||||
code_set_global(access_public);
|
||||
|
||||
attrib_api_export = def_attributes( code(GEN_API_Export_Code));
|
||||
attrib_api_export.set_global();
|
||||
StrC api_export_str = code(GEN_API_Export_Code);
|
||||
attrib_api_export = def_attributes( api_export_str );
|
||||
code_set_global(cast(Code, attrib_api_export));
|
||||
|
||||
attrib_api_import = def_attributes( code(GEN_API_Import_Code));
|
||||
attrib_api_import.set_global();
|
||||
StrC api_import_str = code(GEN_API_Import_Code);
|
||||
attrib_api_import = def_attributes( api_import_str );
|
||||
code_set_global(cast(Code, attrib_api_import));
|
||||
|
||||
module_global_fragment = make_code();
|
||||
module_global_fragment->Type = ECode::Untyped;
|
||||
module_global_fragment->Type = CT_Untyped;
|
||||
module_global_fragment->Name = get_cached_string( txt("module;") );
|
||||
module_global_fragment->Content = module_global_fragment->Name;
|
||||
module_global_fragment.set_global();
|
||||
code_set_global(cast(Code, module_global_fragment));
|
||||
|
||||
module_private_fragment = make_code();
|
||||
module_private_fragment->Type = ECode::Untyped;
|
||||
module_private_fragment->Type = CT_Untyped;
|
||||
module_private_fragment->Name = get_cached_string( txt("module : private;") );
|
||||
module_private_fragment->Content = module_private_fragment->Name;
|
||||
module_private_fragment.set_global();
|
||||
code_set_global(cast(Code, module_private_fragment));
|
||||
|
||||
fmt_newline = make_code();
|
||||
fmt_newline->Type = ECode::NewLine;
|
||||
fmt_newline.set_global();
|
||||
fmt_newline->Type = CT_NewLine;
|
||||
code_set_global((Code)fmt_newline);
|
||||
|
||||
pragma_once = (CodePragma) make_code();
|
||||
pragma_once->Type = ECode::Preprocess_Pragma;
|
||||
pragma_once->Type = CT_Preprocess_Pragma;
|
||||
pragma_once->Name = get_cached_string( txt("once") );
|
||||
pragma_once->Content = pragma_once->Name;
|
||||
pragma_once.set_global();
|
||||
code_set_global((Code)pragma_once);
|
||||
|
||||
param_varadic = (CodeType) make_code();
|
||||
param_varadic->Type = ECode::Parameters;
|
||||
param_varadic = (CodeParam) make_code();
|
||||
param_varadic->Type = CT_Parameters;
|
||||
param_varadic->Name = get_cached_string( txt("...") );
|
||||
param_varadic->ValueType = t_empty;
|
||||
param_varadic.set_global();
|
||||
code_set_global((Code)param_varadic);
|
||||
|
||||
preprocess_else = (CodePreprocessCond) make_code();
|
||||
preprocess_else->Type = ECode::Preprocess_Else;
|
||||
preprocess_else.set_global();
|
||||
preprocess_else->Type = CT_Preprocess_Else;
|
||||
code_set_global((Code)preprocess_else);
|
||||
|
||||
preprocess_endif = (CodePreprocessCond) make_code();
|
||||
preprocess_endif->Type = ECode::Preprocess_EndIf;
|
||||
preprocess_endif.set_global();
|
||||
preprocess_endif->Type = CT_Preprocess_EndIf;
|
||||
code_set_global((Code)preprocess_endif);
|
||||
|
||||
# define def_constant_code_type( Type_ ) \
|
||||
t_##Type_ = def_type( name(Type_) ); \
|
||||
t_##Type_.set_global();
|
||||
do \
|
||||
{ \
|
||||
StrC name_str = name(Type_); \
|
||||
t_##Type_ = def_type( name_str ); \
|
||||
code_set_global( cast(Code, t_##Type_)); \
|
||||
} while(0)
|
||||
|
||||
def_constant_code_type( auto );
|
||||
def_constant_code_type( void );
|
||||
@@ -180,7 +186,7 @@ void define_constants()
|
||||
|
||||
# define def_constant_spec( Type_, ... ) \
|
||||
spec_##Type_ = def_specifiers( num_args(__VA_ARGS__), __VA_ARGS__); \
|
||||
spec_##Type_.set_global();
|
||||
code_set_global( cast(Code, spec_##Type_));
|
||||
|
||||
# pragma push_macro("forceinline")
|
||||
# pragma push_macro("global")
|
||||
@@ -192,33 +198,33 @@ void define_constants()
|
||||
# undef internal
|
||||
# undef local_persist
|
||||
# undef neverinline
|
||||
def_constant_spec( const, ESpecifier::Const );
|
||||
def_constant_spec( consteval, ESpecifier::Consteval );
|
||||
def_constant_spec( constexpr, ESpecifier::Constexpr );
|
||||
def_constant_spec( constinit, ESpecifier::Constinit );
|
||||
def_constant_spec( extern_linkage, ESpecifier::External_Linkage );
|
||||
def_constant_spec( final, ESpecifier::Final );
|
||||
def_constant_spec( forceinline, ESpecifier::ForceInline );
|
||||
def_constant_spec( global, ESpecifier::Global );
|
||||
def_constant_spec( inline, ESpecifier::Inline );
|
||||
def_constant_spec( internal_linkage, ESpecifier::Internal_Linkage );
|
||||
def_constant_spec( local_persist, ESpecifier::Local_Persist );
|
||||
def_constant_spec( mutable, ESpecifier::Mutable );
|
||||
def_constant_spec( neverinline, ESpecifier::NeverInline );
|
||||
def_constant_spec( noexcept, ESpecifier::NoExceptions );
|
||||
def_constant_spec( override, ESpecifier::Override );
|
||||
def_constant_spec( ptr, ESpecifier::Ptr );
|
||||
def_constant_spec( pure, ESpecifier::Pure )
|
||||
def_constant_spec( ref, ESpecifier::Ref );
|
||||
def_constant_spec( register, ESpecifier::Register );
|
||||
def_constant_spec( rvalue, ESpecifier::RValue );
|
||||
def_constant_spec( static_member, ESpecifier::Static );
|
||||
def_constant_spec( thread_local, ESpecifier::Thread_Local );
|
||||
def_constant_spec( virtual, ESpecifier::Virtual );
|
||||
def_constant_spec( volatile, ESpecifier::Volatile)
|
||||
def_constant_spec( const, Spec_Const );
|
||||
def_constant_spec( consteval, Spec_Consteval );
|
||||
def_constant_spec( constexpr, Spec_Constexpr );
|
||||
def_constant_spec( constinit, Spec_Constinit );
|
||||
def_constant_spec( extern_linkage, Spec_External_Linkage );
|
||||
def_constant_spec( final, Spec_Final );
|
||||
def_constant_spec( forceinline, Spec_ForceInline );
|
||||
def_constant_spec( global, Spec_Global );
|
||||
def_constant_spec( inline, Spec_Inline );
|
||||
def_constant_spec( internal_linkage, Spec_Internal_Linkage );
|
||||
def_constant_spec( local_persist, Spec_Local_Persist );
|
||||
def_constant_spec( mutable, Spec_Mutable );
|
||||
def_constant_spec( neverinline, Spec_NeverInline );
|
||||
def_constant_spec( noexcept, Spec_NoExceptions );
|
||||
def_constant_spec( override, Spec_Override );
|
||||
def_constant_spec( ptr, Spec_Ptr );
|
||||
def_constant_spec( pure, Spec_Pure )
|
||||
def_constant_spec( ref, Spec_Ref );
|
||||
def_constant_spec( register, Spec_Register );
|
||||
def_constant_spec( rvalue, Spec_RValue );
|
||||
def_constant_spec( static_member, Spec_Static );
|
||||
def_constant_spec( thread_local, Spec_Thread_Local );
|
||||
def_constant_spec( virtual, Spec_Virtual );
|
||||
def_constant_spec( volatile, Spec_Volatile)
|
||||
|
||||
spec_local_persist = def_specifiers( 1, ESpecifier::Local_Persist );
|
||||
spec_local_persist.set_global();
|
||||
spec_local_persist = def_specifiers( 1, Spec_Local_Persist );
|
||||
code_set_global(cast(Code, spec_local_persist));
|
||||
|
||||
# pragma pop_macro("forceinline")
|
||||
# pragma pop_macro("global")
|
||||
@@ -226,6 +232,10 @@ void define_constants()
|
||||
# pragma pop_macro("local_persist")
|
||||
# pragma pop_macro("neverinline")
|
||||
|
||||
# pragma push_macro("enum_underlying")
|
||||
array_append(PreprocessorDefines, txt("enum_underlying("));
|
||||
# pragma pop_macro("enum_underlying")
|
||||
|
||||
# undef def_constant_spec
|
||||
}
|
||||
|
||||
@@ -233,30 +243,49 @@ void init()
|
||||
{
|
||||
// Setup global allocator
|
||||
{
|
||||
GlobalAllocator = AllocatorInfo { & Global_Allocator_Proc, nullptr };
|
||||
AllocatorInfo becasue_C = { & Global_Allocator_Proc, nullptr };
|
||||
GlobalAllocator = becasue_C;
|
||||
|
||||
Global_AllocatorBuckets = Array<Arena>::init_reserve( heap(), 128 );
|
||||
Global_AllocatorBuckets = array_init_reserve(Arena, heap(), 128 );
|
||||
|
||||
if ( Global_AllocatorBuckets == nullptr )
|
||||
GEN_FATAL( "Failed to reserve memory for Global_AllocatorBuckets");
|
||||
|
||||
Arena bucket = Arena::init_from_allocator( heap(), Global_BucketSize );
|
||||
Arena bucket = arena_init_from_allocator( heap(), Global_BucketSize );
|
||||
|
||||
if ( bucket.PhysicalStart == nullptr )
|
||||
GEN_FATAL( "Failed to create first bucket for Global_AllocatorBuckets");
|
||||
|
||||
Global_AllocatorBuckets.append( bucket );
|
||||
array_append( Global_AllocatorBuckets, bucket );
|
||||
}
|
||||
|
||||
if (Allocator_DataArrays.Proc == nullptr) {
|
||||
Allocator_DataArrays = heap();
|
||||
}
|
||||
if (Allocator_CodePool.Proc == nullptr ) {
|
||||
Allocator_CodePool = heap();
|
||||
}
|
||||
if (Allocator_Lexer.Proc == nullptr) {
|
||||
Allocator_Lexer = heap();
|
||||
}
|
||||
if (Allocator_StringArena.Proc == nullptr) {
|
||||
Allocator_StringArena = heap();
|
||||
}
|
||||
if (Allocator_StringTable.Proc == nullptr) {
|
||||
Allocator_StringTable = heap();
|
||||
}
|
||||
if (Allocator_TypeTable.Proc == nullptr) {
|
||||
Allocator_TypeTable = heap();
|
||||
}
|
||||
|
||||
// Setup the arrays
|
||||
{
|
||||
CodePools = Array<Pool>::init_reserve( Allocator_DataArrays, InitSize_DataArrays );
|
||||
CodePools = array_init_reserve(Pool, Allocator_DataArrays, InitSize_DataArrays );
|
||||
|
||||
if ( CodePools == nullptr )
|
||||
GEN_FATAL( "gen::init: Failed to initialize the CodePools array" );
|
||||
|
||||
StringArenas = Array<Arena>::init_reserve( Allocator_DataArrays, InitSize_DataArrays );
|
||||
StringArenas = array_init_reserve(Arena, Allocator_DataArrays, InitSize_DataArrays );
|
||||
|
||||
if ( StringArenas == nullptr )
|
||||
GEN_FATAL( "gen::init: Failed to initialize the StringArenas array" );
|
||||
@@ -264,97 +293,97 @@ void init()
|
||||
|
||||
// Setup the code pool and code entries arena.
|
||||
{
|
||||
Pool code_pool = Pool::init( Allocator_CodePool, CodePool_NumBlocks, sizeof(AST) );
|
||||
Pool code_pool = pool_init( Allocator_CodePool, CodePool_NumBlocks, sizeof(AST) );
|
||||
|
||||
if ( code_pool.PhysicalStart == nullptr )
|
||||
GEN_FATAL( "gen::init: Failed to initialize the code pool" );
|
||||
|
||||
CodePools.append( code_pool );
|
||||
array_append( CodePools, code_pool );
|
||||
|
||||
LexArena = Arena::init_from_allocator( Allocator_Lexer, LexAllocator_Size );
|
||||
LexArena = arena_init_from_allocator( Allocator_Lexer, LexAllocator_Size );
|
||||
|
||||
Arena string_arena = Arena::init_from_allocator( Allocator_StringArena, SizePer_StringArena );
|
||||
Arena string_arena = arena_init_from_allocator( Allocator_StringArena, SizePer_StringArena );
|
||||
|
||||
if ( string_arena.PhysicalStart == nullptr )
|
||||
GEN_FATAL( "gen::init: Failed to initialize the string arena" );
|
||||
|
||||
StringArenas.append( string_arena );
|
||||
array_append( StringArenas, string_arena );
|
||||
}
|
||||
|
||||
// Setup the hash tables
|
||||
{
|
||||
StringCache = StringTable::init( Allocator_StringTable );
|
||||
StringCache = hashtable_init(StringCached, Allocator_StringTable);
|
||||
|
||||
if ( StringCache.Entries == nullptr )
|
||||
GEN_FATAL( "gen::init: Failed to initialize the StringCache");
|
||||
}
|
||||
|
||||
// Preprocessor Defines
|
||||
PreprocessorDefines = Array<StringCached>::init_reserve( GlobalAllocator, kilobytes(1) );
|
||||
PreprocessorDefines = array_init_reserve(StringCached, GlobalAllocator, kilobytes(1) );
|
||||
|
||||
define_constants();
|
||||
parser::init();
|
||||
GEN_NS_PARSER parser_init();
|
||||
}
|
||||
|
||||
void deinit()
|
||||
{
|
||||
usize index = 0;
|
||||
usize left = CodePools.num();
|
||||
usize left = array_num(CodePools);
|
||||
do
|
||||
{
|
||||
Pool* code_pool = & CodePools[index];
|
||||
code_pool->free();
|
||||
pool_free(code_pool);
|
||||
index++;
|
||||
}
|
||||
while ( left--, left );
|
||||
|
||||
index = 0;
|
||||
left = StringArenas.num();
|
||||
left = array_num(StringArenas);
|
||||
do
|
||||
{
|
||||
Arena* string_arena = & StringArenas[index];
|
||||
string_arena->free();
|
||||
arena_free(string_arena);
|
||||
index++;
|
||||
}
|
||||
while ( left--, left );
|
||||
|
||||
StringCache.destroy();
|
||||
hashtable_destroy(StringCache);
|
||||
|
||||
CodePools.free();
|
||||
StringArenas.free();
|
||||
array_free( CodePools);
|
||||
array_free( StringArenas);
|
||||
|
||||
LexArena.free();
|
||||
arena_free(& LexArena);
|
||||
|
||||
PreprocessorDefines.free();
|
||||
array_free(PreprocessorDefines);
|
||||
|
||||
index = 0;
|
||||
left = Global_AllocatorBuckets.num();
|
||||
left = array_num(Global_AllocatorBuckets);
|
||||
do
|
||||
{
|
||||
Arena* bucket = & Global_AllocatorBuckets[ index ];
|
||||
bucket->free();
|
||||
arena_free(bucket);
|
||||
index++;
|
||||
}
|
||||
while ( left--, left );
|
||||
|
||||
Global_AllocatorBuckets.free();
|
||||
parser::deinit();
|
||||
array_free(Global_AllocatorBuckets);
|
||||
GEN_NS_PARSER parser_deinit();
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
s32 index = 0;
|
||||
s32 left = CodePools.num();
|
||||
s32 left = array_num(CodePools);
|
||||
do
|
||||
{
|
||||
Pool* code_pool = & CodePools[index];
|
||||
code_pool->clear();
|
||||
pool_clear(code_pool);
|
||||
index++;
|
||||
}
|
||||
while ( left--, left );
|
||||
|
||||
index = 0;
|
||||
left = StringArenas.num();
|
||||
left = array_num(StringArenas);
|
||||
do
|
||||
{
|
||||
Arena* string_arena = & StringArenas[index];
|
||||
@@ -363,28 +392,28 @@ void reset()
|
||||
}
|
||||
while ( left--, left );
|
||||
|
||||
StringCache.clear();
|
||||
hashtable_clear(StringCache);
|
||||
|
||||
define_constants();
|
||||
}
|
||||
|
||||
AllocatorInfo get_string_allocator( s32 str_length )
|
||||
{
|
||||
Arena* last = & StringArenas.back();
|
||||
Arena* last = array_back(StringArenas);
|
||||
|
||||
usize size_req = str_length + sizeof(String::Header) + sizeof(char*);
|
||||
usize size_req = str_length + sizeof(StringHeader) + sizeof(char*);
|
||||
|
||||
if ( last->TotalUsed + ssize(size_req) > last->TotalSize )
|
||||
if ( last->TotalUsed + scast(ssize, size_req) > last->TotalSize )
|
||||
{
|
||||
Arena new_arena = Arena::init_from_allocator( Allocator_StringArena, SizePer_StringArena );
|
||||
Arena new_arena = arena_init_from_allocator( Allocator_StringArena, SizePer_StringArena );
|
||||
|
||||
if ( ! StringArenas.append( new_arena ) )
|
||||
if ( ! array_append( StringArenas, new_arena ) )
|
||||
GEN_FATAL( "gen::get_string_allocator: Failed to allocate a new string arena" );
|
||||
|
||||
last = & StringArenas.back();
|
||||
last = array_back(StringArenas);
|
||||
}
|
||||
|
||||
return * last;
|
||||
return arena_allocator_info(last);
|
||||
}
|
||||
|
||||
// Will either make or retrive a code string.
|
||||
@@ -393,14 +422,14 @@ StringCached get_cached_string( StrC str )
|
||||
s32 hash_length = str.Len > kilobytes(1) ? kilobytes(1) : str.Len;
|
||||
u64 key = crc32( str.Ptr, hash_length );
|
||||
{
|
||||
StringCached* result = StringCache.get( key );
|
||||
StringCached* result = hashtable_get(StringCache, key );
|
||||
|
||||
if ( result )
|
||||
return * result;
|
||||
}
|
||||
|
||||
String result = String::make( get_string_allocator( str.Len ), str );
|
||||
StringCache.set( key, result );
|
||||
StrC result = string_to_strc( string_make_strc( get_string_allocator( str.Len ), str ));
|
||||
hashtable_set(StringCache, key, result );
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -408,34 +437,22 @@ StringCached get_cached_string( StrC str )
|
||||
// Used internally to retireve a Code object form the CodePool.
|
||||
Code make_code()
|
||||
{
|
||||
Pool* allocator = & CodePools.back();
|
||||
Pool* allocator = array_back( CodePools);
|
||||
if ( allocator->FreeList == nullptr )
|
||||
{
|
||||
Pool code_pool = Pool::init( Allocator_CodePool, CodePool_NumBlocks, sizeof(AST) );
|
||||
Pool code_pool = pool_init( Allocator_CodePool, CodePool_NumBlocks, sizeof(AST) );
|
||||
|
||||
if ( code_pool.PhysicalStart == nullptr )
|
||||
GEN_FATAL( "gen::make_code: Failed to allocate a new code pool - CodePool allcoator returned nullptr." );
|
||||
|
||||
if ( ! CodePools.append( code_pool ) )
|
||||
if ( ! array_append( CodePools, code_pool ) )
|
||||
GEN_FATAL( "gen::make_code: Failed to allocate a new code pool - CodePools failed to append new pool." );
|
||||
|
||||
allocator = & CodePools.back();
|
||||
allocator = array_back( CodePools);
|
||||
}
|
||||
|
||||
Code result { rcast( AST*, alloc( * allocator, sizeof(AST) )) };
|
||||
mem_set( result.ast, 0, sizeof(AST) );
|
||||
// result->Type = ECode::Invalid;
|
||||
|
||||
// result->Content = { nullptr };
|
||||
// result->Prev = { nullptr };
|
||||
// result->Next = { nullptr };
|
||||
// result->Token = nullptr;
|
||||
// result->Parent = { nullptr };
|
||||
// result->Name = { nullptr };
|
||||
// result->Type = ECode::Invalid;
|
||||
// result->ModuleFlags = ModuleFlag::Invalid;
|
||||
// result->NumEntries = 0;
|
||||
|
||||
Code result = { rcast( AST*, alloc( pool_allocator_info(allocator), sizeof(AST) )) };
|
||||
mem_set( rcast(void*, cast(AST*, result)), 0, sizeof(AST) );
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,9 +4,18 @@
|
||||
#endif
|
||||
|
||||
#pragma region Gen Interface
|
||||
/*
|
||||
/ \ | \ | \ / \
|
||||
| ▓▓▓▓▓▓\ ______ _______ \▓▓▓▓▓▓_______ _| ▓▓_ ______ ______ | ▓▓▓▓▓▓\ ______ _______ ______
|
||||
| ▓▓ __\▓▓/ \| \ | ▓▓ | \| ▓▓ \ / \ / \| ▓▓_ \▓▓| \ / \/ \
|
||||
| ▓▓| \ ▓▓▓▓▓▓\ ▓▓▓▓▓▓▓\ | ▓▓ | ▓▓▓▓▓▓▓\\▓▓▓▓▓▓ | ▓▓▓▓▓▓\ ▓▓▓▓▓▓\ ▓▓ \ \▓▓▓▓▓▓\ ▓▓▓▓▓▓▓ ▓▓▓▓▓▓\
|
||||
| ▓▓ \▓▓▓▓ ▓▓ ▓▓ ▓▓ | ▓▓ | ▓▓ | ▓▓ | ▓▓ | ▓▓ __| ▓▓ ▓▓ ▓▓ \▓▓ ▓▓▓▓ / ▓▓ ▓▓ | ▓▓ ▓▓
|
||||
| ▓▓__| ▓▓ ▓▓▓▓▓▓▓▓ ▓▓ | ▓▓ _| ▓▓_| ▓▓ | ▓▓ | ▓▓| \ ▓▓▓▓▓▓▓▓ ▓▓ | ▓▓ | ▓▓▓▓▓▓▓ ▓▓_____| ▓▓▓▓▓▓▓▓
|
||||
\▓▓ ▓▓\▓▓ \ ▓▓ | ▓▓ | ▓▓ \ ▓▓ | ▓▓ \▓▓ ▓▓\▓▓ \ ▓▓ | ▓▓ \▓▓ ▓▓\▓▓ \\▓▓ \
|
||||
\▓▓▓▓▓▓ \▓▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓ \▓▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓
|
||||
*/
|
||||
|
||||
// Initialize the library.
|
||||
// This currently just initializes the CodePool.
|
||||
void init();
|
||||
|
||||
// Currently manually free's the arenas, code for checking for leaks.
|
||||
@@ -42,77 +51,130 @@ void set_allocator_type_table ( AllocatorInfo type_reg_allocator );
|
||||
CodeAttributes def_attributes( StrC content );
|
||||
CodeComment def_comment ( StrC content );
|
||||
|
||||
CodeClass def_class( StrC name
|
||||
, Code body = NoCode
|
||||
, CodeType parent = NoCode, AccessSpec access = AccessSpec::Default
|
||||
, CodeAttributes attributes = NoCode
|
||||
, ModuleFlag mflags = ModuleFlag::None
|
||||
, CodeType* interfaces = nullptr, s32 num_interfaces = 0 );
|
||||
struct Opts_def_struct {
|
||||
CodeBody body;
|
||||
CodeTypename parent;
|
||||
AccessSpec parent_access;
|
||||
CodeAttributes attributes;
|
||||
CodeTypename* interfaces;
|
||||
s32 num_interfaces;
|
||||
ModuleFlag mflags;
|
||||
};
|
||||
CodeClass def_class( StrC name, Opts_def_struct otps GEN_PARAM_DEFAULT );
|
||||
|
||||
CodeConstructor def_constructor( CodeParam params = NoCode, Code initializer_list = NoCode, Code body = NoCode );
|
||||
struct Opts_def_constructor {
|
||||
CodeParam params;
|
||||
Code initializer_list;
|
||||
Code body;
|
||||
};
|
||||
CodeConstructor def_constructor( Opts_def_constructor opts GEN_PARAM_DEFAULT );
|
||||
|
||||
CodeDefine def_define( StrC name, StrC content );
|
||||
|
||||
CodeDestructor def_destructor( Code body = NoCode, CodeSpecifiers specifiers = NoCode );
|
||||
struct Opts_def_destructor {
|
||||
Code body;
|
||||
CodeSpecifiers specifiers;
|
||||
};
|
||||
CodeDestructor def_destructor( Opts_def_destructor opts GEN_PARAM_DEFAULT );
|
||||
|
||||
CodeEnum def_enum( StrC name
|
||||
, Code body = NoCode, CodeType type = NoCode
|
||||
, EnumT specifier = EnumRegular, CodeAttributes attributes = NoCode
|
||||
, ModuleFlag mflags = ModuleFlag::None );
|
||||
struct Opts_def_enum {
|
||||
CodeBody body;
|
||||
CodeTypename type;
|
||||
EnumT specifier;
|
||||
CodeAttributes attributes;
|
||||
ModuleFlag mflags;
|
||||
};
|
||||
CodeEnum def_enum( StrC name, Opts_def_enum opts GEN_PARAM_DEFAULT );
|
||||
|
||||
CodeExec def_execution ( StrC content );
|
||||
CodeExtern def_extern_link( StrC name, Code body );
|
||||
CodeExtern def_extern_link( StrC name, CodeBody body );
|
||||
CodeFriend def_friend ( Code symbol );
|
||||
|
||||
CodeFn def_function( StrC name
|
||||
, CodeParam params = NoCode, CodeType ret_type = NoCode, Code body = NoCode
|
||||
, CodeSpecifiers specifiers = NoCode, CodeAttributes attributes = NoCode
|
||||
, ModuleFlag mflags = ModuleFlag::None );
|
||||
struct Opts_def_function {
|
||||
CodeParam params;
|
||||
CodeTypename ret_type;
|
||||
CodeBody body;
|
||||
CodeSpecifiers specs;
|
||||
CodeAttributes attrs;
|
||||
ModuleFlag mflags;
|
||||
};
|
||||
CodeFn def_function( StrC name, Opts_def_function opts GEN_PARAM_DEFAULT );
|
||||
|
||||
CodeInclude def_include ( StrC content, bool foreign = false );
|
||||
CodeModule def_module ( StrC name, ModuleFlag mflags = ModuleFlag::None );
|
||||
CodeNS def_namespace( StrC name, Code body, ModuleFlag mflags = ModuleFlag::None );
|
||||
struct Opts_def_include { b32 foreign; };
|
||||
struct Opts_def_module { ModuleFlag mflags; };
|
||||
struct Opts_def_namespace { ModuleFlag mflags; };
|
||||
CodeInclude def_include ( StrC content, Opts_def_include opts GEN_PARAM_DEFAULT );
|
||||
CodeModule def_module ( StrC name, Opts_def_module opts GEN_PARAM_DEFAULT );
|
||||
CodeNS def_namespace( StrC name, CodeBody body, Opts_def_namespace opts GEN_PARAM_DEFAULT );
|
||||
|
||||
CodeOperator def_operator( OperatorT op, StrC nspace
|
||||
, CodeParam params = NoCode, CodeType ret_type = NoCode, Code body = NoCode
|
||||
, CodeSpecifiers specifiers = NoCode, CodeAttributes attributes = NoCode
|
||||
, ModuleFlag mflags = ModuleFlag::None );
|
||||
struct Opts_def_operator {
|
||||
CodeParam params;
|
||||
CodeTypename ret_type;
|
||||
CodeBody body;
|
||||
CodeSpecifiers specifiers;
|
||||
CodeAttributes attributes;
|
||||
ModuleFlag mflags;
|
||||
};
|
||||
CodeOperator def_operator( Operator op, StrC nspace, Opts_def_operator opts GEN_PARAM_DEFAULT );
|
||||
|
||||
CodeOpCast def_operator_cast( CodeType type, Code body = NoCode, CodeSpecifiers specs = NoCode );
|
||||
struct Opts_def_operator_cast {
|
||||
CodeBody body;
|
||||
CodeSpecifiers specs;
|
||||
};
|
||||
CodeOpCast def_operator_cast( CodeTypename type, Opts_def_operator_cast opts GEN_PARAM_DEFAULT );
|
||||
|
||||
CodeParam def_param ( CodeType type, StrC name, Code value = NoCode );
|
||||
struct Opts_def_param { Code value; };
|
||||
CodeParam def_param ( CodeTypename type, StrC name, Opts_def_param opts GEN_PARAM_DEFAULT );
|
||||
CodePragma def_pragma( StrC directive );
|
||||
|
||||
CodePreprocessCond def_preprocess_cond( EPreprocessCond type, StrC content );
|
||||
|
||||
CodeSpecifiers def_specifier( SpecifierT specifier );
|
||||
CodeSpecifiers def_specifier( Specifier specifier );
|
||||
|
||||
CodeStruct def_struct( StrC name
|
||||
, Code body = NoCode
|
||||
, CodeType parent = NoCode, AccessSpec access = AccessSpec::Default
|
||||
, CodeAttributes attributes = NoCode
|
||||
, ModuleFlag mflags = ModuleFlag::None
|
||||
, CodeType* interfaces = nullptr, s32 num_interfaces = 0 );
|
||||
CodeStruct def_struct( StrC name, Opts_def_struct opts GEN_PARAM_DEFAULT );
|
||||
|
||||
CodeTemplate def_template( CodeParam params, Code definition, ModuleFlag mflags = ModuleFlag::None );
|
||||
struct Opts_def_template { ModuleFlag mflags; };
|
||||
CodeTemplate def_template( CodeParam params, Code definition, Opts_def_template opts GEN_PARAM_DEFAULT );
|
||||
|
||||
CodeType def_type ( StrC name, Code arrayexpr = NoCode, CodeSpecifiers specifiers = NoCode, CodeAttributes attributes = NoCode );
|
||||
CodeTypedef def_typedef( StrC name, Code type, CodeAttributes attributes = NoCode, ModuleFlag mflags = ModuleFlag::None );
|
||||
struct Opts_def_type {
|
||||
ETypenameTag type_tag;
|
||||
Code arrayexpr;
|
||||
CodeSpecifiers specifiers;
|
||||
CodeAttributes attributes;
|
||||
};
|
||||
CodeTypename def_type( StrC name, Opts_def_type opts GEN_PARAM_DEFAULT );
|
||||
|
||||
CodeUnion def_union( StrC name, Code body, CodeAttributes attributes = NoCode, ModuleFlag mflags = ModuleFlag::None );
|
||||
struct Opts_def_typedef {
|
||||
CodeAttributes attributes;
|
||||
ModuleFlag mflags;
|
||||
};
|
||||
CodeTypedef def_typedef( StrC name, Code type, Opts_def_typedef opts GEN_PARAM_DEFAULT );
|
||||
|
||||
CodeUsing def_using( StrC name, CodeType type = NoCode
|
||||
, CodeAttributes attributess = NoCode
|
||||
, ModuleFlag mflags = ModuleFlag::None );
|
||||
struct Opts_def_union {
|
||||
CodeAttributes attributes;
|
||||
ModuleFlag mflags;
|
||||
};
|
||||
CodeUnion def_union( StrC name, CodeBody body, Opts_def_union opts GEN_PARAM_DEFAULT );
|
||||
|
||||
struct Opts_def_using {
|
||||
CodeAttributes attributes;
|
||||
ModuleFlag mflags;
|
||||
};
|
||||
CodeUsing def_using( StrC name, CodeTypename type, Opts_def_using opts GEN_PARAM_DEFAULT );
|
||||
|
||||
CodeUsing def_using_namespace( StrC name );
|
||||
|
||||
CodeVar def_variable( CodeType type, StrC name, Code value = NoCode
|
||||
, CodeSpecifiers specifiers = NoCode, CodeAttributes attributes = NoCode
|
||||
, ModuleFlag mflags = ModuleFlag::None );
|
||||
struct Opts_def_variable
|
||||
{
|
||||
Code value;
|
||||
CodeSpecifiers specifiers;
|
||||
CodeAttributes attributes;
|
||||
ModuleFlag mflags;
|
||||
};
|
||||
CodeVar def_variable( CodeTypename type, StrC name, Opts_def_variable opts GEN_PARAM_DEFAULT );
|
||||
|
||||
// Constructs an empty body. Use AST::validate_body() to check if the body is was has valid entries.
|
||||
CodeBody def_body( CodeT type );
|
||||
CodeBody def_body( CodeType type );
|
||||
|
||||
// There are two options for defining a struct body, either varadically provided with the args macro to auto-deduce the arg num,
|
||||
/// or provide as an array of Code objects.
|
||||
@@ -134,7 +196,7 @@ CodeBody def_namespace_body ( s32 num, Code* codes );
|
||||
CodeParam def_params ( s32 num, ... );
|
||||
CodeParam def_params ( s32 num, CodeParam* params );
|
||||
CodeSpecifiers def_specifiers ( s32 num, ... );
|
||||
CodeSpecifiers def_specifiers ( s32 num, SpecifierT* specs );
|
||||
CodeSpecifiers def_specifiers ( s32 num, Specifier* specs );
|
||||
CodeBody def_struct_body ( s32 num, ... );
|
||||
CodeBody def_struct_body ( s32 num, Code* codes );
|
||||
CodeBody def_union_body ( s32 num, ... );
|
||||
@@ -147,7 +209,7 @@ CodeBody def_union_body ( s32 num, Code* codes );
|
||||
// TODO(Ed) : Implmeent the new parser API design.
|
||||
|
||||
#if 0
|
||||
namespace parser {
|
||||
GEN_NS_PARSER_BEGIN
|
||||
struct StackNode
|
||||
{
|
||||
StackNode* Prev;
|
||||
@@ -163,7 +225,7 @@ namespace parser {
|
||||
String message;
|
||||
StackNode* context_stack;
|
||||
};
|
||||
}
|
||||
GEN_NS_PARSER_END
|
||||
|
||||
struct ParseInfo
|
||||
{
|
||||
@@ -172,8 +234,8 @@ struct ParseInfo
|
||||
Arena CodeMem;
|
||||
|
||||
FileContents FileContent;
|
||||
Array<parser::Token> Tokens;
|
||||
Array<parser::Error> Errors;
|
||||
Array<Token> Tokens;
|
||||
Array<Error> Errors;
|
||||
// Errors are allocated to a dedicated general arena.
|
||||
};
|
||||
|
||||
@@ -194,7 +256,7 @@ CodeOperator parse_operator ( StrC operator_def );
|
||||
CodeOpCast parse_operator_cast( StrC operator_def );
|
||||
CodeStruct parse_struct ( StrC struct_def );
|
||||
CodeTemplate parse_template ( StrC template_def );
|
||||
CodeType parse_type ( StrC type_def );
|
||||
CodeTypename parse_type ( StrC type_def );
|
||||
CodeTypedef parse_typedef ( StrC typedef_def );
|
||||
CodeUnion parse_union ( StrC union_def );
|
||||
CodeUsing parse_using ( StrC using_def );
|
||||
@@ -214,4 +276,55 @@ Code untyped_token_fmt( char const* fmt, s32 num_tokens, ... );
|
||||
|
||||
#pragma endregion Untyped text
|
||||
|
||||
#pragma region Macros
|
||||
|
||||
#ifndef token_fmt
|
||||
# define gen_main main
|
||||
|
||||
# define __ NullCode
|
||||
|
||||
// Convienence for defining any name used with the gen api.
|
||||
// Lets you provide the length and string literal to the functions without the need for the DSL.
|
||||
# define name( Id_ ) { sizeof(stringize( Id_ )) - 1, stringize(Id_) }
|
||||
|
||||
// Same as name just used to indicate intention of literal for code instead of names.
|
||||
# define code( ... ) { sizeof(stringize(__VA_ARGS__)) - 1, stringize( __VA_ARGS__ ) }
|
||||
|
||||
// Provides the number of arguments while passing args inplace.
|
||||
# define args( ... ) num_args( __VA_ARGS__ ), __VA_ARGS__
|
||||
|
||||
// Just wrappers over common untyped code definition constructions.
|
||||
# define code_str( ... ) GEN_NS untyped_str( code( __VA_ARGS__ ) )
|
||||
# define code_fmt( ... ) GEN_NS untyped_str( token_fmt( __VA_ARGS__ ) )
|
||||
|
||||
# define parse_fmt( type, ... ) GEN_NS parse_##type( token_fmt( __VA_ARGS__ ) )
|
||||
|
||||
/*
|
||||
Takes a format string (char const*) and a list of tokens (StrC) and returns a StrC of the formatted string.
|
||||
Tokens are provided in '<'identifier'>' format where '<' '>' are just angle brackets (you can change it in token_fmt_va)
|
||||
---------------------------------------------------------
|
||||
Example - A string with:
|
||||
typedef <type> <name> <name>;
|
||||
Will have a token_fmt arguments populated with:
|
||||
"type", strc_for_type,
|
||||
"name", strc_for_name,
|
||||
and:
|
||||
stringize( typedef <type> <name> <name>; )
|
||||
-----------------------------------------------------------
|
||||
So the full call for this example would be:
|
||||
token_fmt(
|
||||
"type", strc_for_type
|
||||
, "name", strc_for_name
|
||||
, stringize(
|
||||
typedef <type> <name> <name>
|
||||
));
|
||||
!----------------------------------------------------------
|
||||
! Note: token_fmt_va is whitespace sensitive for the tokens.
|
||||
! This can be alleviated by skipping whitespace between brackets but it was choosen to not have that implementation by default.
|
||||
*/
|
||||
# define token_fmt( ... ) GEN_NS token_fmt_impl( (num_args( __VA_ARGS__ ) + 1) / 2, __VA_ARGS__ )
|
||||
#endif
|
||||
|
||||
#pragma endregion Macros
|
||||
|
||||
#pragma endregion Gen Interface
|
||||
|
||||
@@ -10,58 +10,58 @@
|
||||
|
||||
CodeClass parse_class( StrC def )
|
||||
{
|
||||
GEN_USING_NS_PARSER;
|
||||
check_parse_args( def );
|
||||
using namespace parser;
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
return CodeInvalid;
|
||||
return InvalidCode;
|
||||
|
||||
Context.Tokens = toks;
|
||||
push_scope();
|
||||
CodeClass result = (CodeClass) parse_class_struct( TokType::Decl_Class );
|
||||
Context.pop();
|
||||
CodeClass result = (CodeClass) parse_class_struct( Tok_Decl_Class );
|
||||
parser_pop(& Context);
|
||||
return result;
|
||||
}
|
||||
|
||||
CodeConstructor parse_constructor( StrC def )
|
||||
{
|
||||
GEN_USING_NS_PARSER;
|
||||
check_parse_args( def );
|
||||
using namespace parser;
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
return CodeInvalid;
|
||||
return InvalidCode;
|
||||
|
||||
// TODO(Ed): Constructors can have prefix attributes
|
||||
|
||||
CodeSpecifiers specifiers;
|
||||
SpecifierT specs_found[ 16 ] { ESpecifier::NumSpecifiers };
|
||||
Specifier specs_found[ 16 ] { Spec_NumSpecifiers };
|
||||
s32 NumSpecifiers = 0;
|
||||
|
||||
while ( left && currtok.is_specifier() )
|
||||
while ( left && tok_is_specifier(currtok) )
|
||||
{
|
||||
SpecifierT spec = ESpecifier::to_type( currtok );
|
||||
Specifier spec = strc_to_specifier( tok_to_str(currtok) );
|
||||
|
||||
b32 ignore_spec = false;
|
||||
|
||||
switch ( spec )
|
||||
{
|
||||
case ESpecifier::Constexpr :
|
||||
case ESpecifier::Explicit:
|
||||
case ESpecifier::Inline :
|
||||
case ESpecifier::ForceInline :
|
||||
case ESpecifier::NeverInline :
|
||||
case Spec_Constexpr :
|
||||
case Spec_Explicit:
|
||||
case Spec_Inline :
|
||||
case Spec_ForceInline :
|
||||
case Spec_NeverInline :
|
||||
break;
|
||||
|
||||
case ESpecifier::Const :
|
||||
case Spec_Const :
|
||||
ignore_spec = true;
|
||||
break;
|
||||
|
||||
default :
|
||||
log_failure( "Invalid specifier %s for variable\n%s", ESpecifier::to_str( spec ), Context.to_string() );
|
||||
Context.pop();
|
||||
return CodeInvalid;
|
||||
log_failure( "Invalid specifier %s for variable\n%s", spec_to_str( spec ), parser_to_string(Context) );
|
||||
parser_pop(& Context);
|
||||
return InvalidCode;
|
||||
}
|
||||
|
||||
// Every specifier after would be considered part of the type type signature
|
||||
@@ -86,12 +86,12 @@ CodeConstructor parse_constructor( StrC def )
|
||||
|
||||
CodeDestructor parse_destructor( StrC def )
|
||||
{
|
||||
GEN_USING_NS_PARSER;
|
||||
check_parse_args( def );
|
||||
using namespace parser;
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
return CodeInvalid;
|
||||
return InvalidCode;
|
||||
|
||||
// TODO(Ed): Destructors can have prefix attributes
|
||||
// TODO(Ed): Destructors can have virtual
|
||||
@@ -103,28 +103,28 @@ CodeDestructor parse_destructor( StrC def )
|
||||
|
||||
CodeEnum parse_enum( StrC def )
|
||||
{
|
||||
GEN_USING_NS_PARSER;
|
||||
check_parse_args( def );
|
||||
using namespace parser;
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
{
|
||||
Context.pop();
|
||||
return CodeInvalid;
|
||||
parser_pop(& Context);
|
||||
return InvalidCode;
|
||||
}
|
||||
|
||||
Context.Tokens = toks;
|
||||
return parse_enum();
|
||||
return parse_enum( parser_not_inplace_def);
|
||||
}
|
||||
|
||||
CodeBody parse_export_body( StrC def )
|
||||
{
|
||||
GEN_USING_NS_PARSER;
|
||||
check_parse_args( def );
|
||||
using namespace parser;
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
return CodeInvalid;
|
||||
return InvalidCode;
|
||||
|
||||
Context.Tokens = toks;
|
||||
return parse_export_body();
|
||||
@@ -132,12 +132,12 @@ CodeBody parse_export_body( StrC def )
|
||||
|
||||
CodeExtern parse_extern_link( StrC def )
|
||||
{
|
||||
GEN_USING_NS_PARSER;
|
||||
check_parse_args( def );
|
||||
using namespace parser;
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
return CodeInvalid;
|
||||
return InvalidCode;
|
||||
|
||||
Context.Tokens = toks;
|
||||
return parse_extern_link();
|
||||
@@ -145,12 +145,12 @@ CodeExtern parse_extern_link( StrC def )
|
||||
|
||||
CodeFriend parse_friend( StrC def )
|
||||
{
|
||||
GEN_USING_NS_PARSER;
|
||||
check_parse_args( def );
|
||||
using namespace parser;
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
return CodeInvalid;
|
||||
return InvalidCode;
|
||||
|
||||
Context.Tokens = toks;
|
||||
return parse_friend();
|
||||
@@ -158,12 +158,12 @@ CodeFriend parse_friend( StrC def )
|
||||
|
||||
CodeFn parse_function( StrC def )
|
||||
{
|
||||
GEN_USING_NS_PARSER;
|
||||
check_parse_args( def );
|
||||
using namespace parser;
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
return CodeInvalid;
|
||||
return InvalidCode;
|
||||
|
||||
Context.Tokens = toks;
|
||||
return (CodeFn) parse_function();
|
||||
@@ -171,28 +171,28 @@ CodeFn parse_function( StrC def )
|
||||
|
||||
CodeBody parse_global_body( StrC def )
|
||||
{
|
||||
GEN_USING_NS_PARSER;
|
||||
check_parse_args( def );
|
||||
using namespace parser;
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
return CodeInvalid;
|
||||
return InvalidCode;
|
||||
|
||||
Context.Tokens = toks;
|
||||
push_scope();
|
||||
CodeBody result = parse_global_nspace( ECode::Global_Body );
|
||||
Context.pop();
|
||||
CodeBody result = parse_global_nspace( CT_Global_Body );
|
||||
parser_pop(& Context);
|
||||
return result;
|
||||
}
|
||||
|
||||
CodeNS parse_namespace( StrC def )
|
||||
{
|
||||
GEN_USING_NS_PARSER;
|
||||
check_parse_args( def );
|
||||
using namespace parser;
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
return CodeInvalid;
|
||||
return InvalidCode;
|
||||
|
||||
Context.Tokens = toks;
|
||||
return parse_namespace();
|
||||
@@ -200,12 +200,12 @@ CodeNS parse_namespace( StrC def )
|
||||
|
||||
CodeOperator parse_operator( StrC def )
|
||||
{
|
||||
GEN_USING_NS_PARSER;
|
||||
check_parse_args( def );
|
||||
using namespace parser;
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
return CodeInvalid;
|
||||
return InvalidCode;
|
||||
|
||||
Context.Tokens = toks;
|
||||
return (CodeOperator) parse_operator();
|
||||
@@ -213,12 +213,12 @@ CodeOperator parse_operator( StrC def )
|
||||
|
||||
CodeOpCast parse_operator_cast( StrC def )
|
||||
{
|
||||
GEN_USING_NS_PARSER;
|
||||
check_parse_args( def );
|
||||
using namespace parser;
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
return CodeInvalid;
|
||||
return InvalidCode;
|
||||
|
||||
Context.Tokens = toks;
|
||||
return parse_operator_cast();
|
||||
@@ -226,54 +226,54 @@ CodeOpCast parse_operator_cast( StrC def )
|
||||
|
||||
CodeStruct parse_struct( StrC def )
|
||||
{
|
||||
GEN_USING_NS_PARSER;
|
||||
check_parse_args( def );
|
||||
using namespace parser;
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
return CodeInvalid;
|
||||
return InvalidCode;
|
||||
|
||||
Context.Tokens = toks;
|
||||
push_scope();
|
||||
CodeStruct result = (CodeStruct) parse_class_struct( TokType::Decl_Struct );
|
||||
Context.pop();
|
||||
CodeStruct result = (CodeStruct) parse_class_struct( Tok_Decl_Struct );
|
||||
parser_pop(& Context);
|
||||
return result;
|
||||
}
|
||||
|
||||
CodeTemplate parse_template( StrC def )
|
||||
{
|
||||
GEN_USING_NS_PARSER;
|
||||
check_parse_args( def );
|
||||
using namespace parser;
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
return CodeInvalid;
|
||||
return InvalidCode;
|
||||
|
||||
Context.Tokens = toks;
|
||||
return parse_template();
|
||||
}
|
||||
|
||||
CodeType parse_type( StrC def )
|
||||
CodeTypename parse_type( StrC def )
|
||||
{
|
||||
GEN_USING_NS_PARSER;
|
||||
check_parse_args( def );
|
||||
using namespace parser;
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
return CodeInvalid;
|
||||
return InvalidCode;
|
||||
|
||||
Context.Tokens = toks;
|
||||
return parse_type();
|
||||
return parse_type( parser_not_from_template, nullptr);
|
||||
}
|
||||
|
||||
CodeTypedef parse_typedef( StrC def )
|
||||
{
|
||||
GEN_USING_NS_PARSER;
|
||||
check_parse_args( def );
|
||||
using namespace parser;
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
return CodeInvalid;
|
||||
return InvalidCode;
|
||||
|
||||
Context.Tokens = toks;
|
||||
return parse_typedef();
|
||||
@@ -281,25 +281,25 @@ CodeTypedef parse_typedef( StrC def )
|
||||
|
||||
CodeUnion parse_union( StrC def )
|
||||
{
|
||||
GEN_USING_NS_PARSER;
|
||||
check_parse_args( def );
|
||||
using namespace parser;
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
return CodeInvalid;
|
||||
return InvalidCode;
|
||||
|
||||
Context.Tokens = toks;
|
||||
return parse_union();
|
||||
return parse_union( parser_not_inplace_def);
|
||||
}
|
||||
|
||||
CodeUsing parse_using( StrC def )
|
||||
{
|
||||
GEN_USING_NS_PARSER;
|
||||
check_parse_args( def );
|
||||
using namespace parser;
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
return CodeInvalid;
|
||||
return InvalidCode;
|
||||
|
||||
Context.Tokens = toks;
|
||||
return parse_using();
|
||||
@@ -307,12 +307,12 @@ CodeUsing parse_using( StrC def )
|
||||
|
||||
CodeVar parse_variable( StrC def )
|
||||
{
|
||||
GEN_USING_NS_PARSER;
|
||||
check_parse_args( def );
|
||||
using namespace parser;
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
return CodeInvalid;
|
||||
return InvalidCode;
|
||||
|
||||
Context.Tokens = toks;
|
||||
return parse_variable();
|
||||
|
||||
@@ -9,15 +9,13 @@ ssize token_fmt_va( char* buf, usize buf_size, s32 num_tokens, va_list va )
|
||||
ssize remaining = buf_size;
|
||||
|
||||
local_persist
|
||||
Arena tok_map_arena;
|
||||
FixedArena<TokenFmt_TokenMap_MemSize> tok_map_arena;
|
||||
fixed_arena_init( & tok_map_arena);
|
||||
|
||||
HashTable<StrC> tok_map;
|
||||
{
|
||||
local_persist
|
||||
char tok_map_mem[ TokenFmt_TokenMap_MemSize ];
|
||||
|
||||
tok_map_arena = Arena::init_from_memory( tok_map_mem, sizeof(tok_map_mem) );
|
||||
tok_map = HashTable<StrC>::init( tok_map_arena );
|
||||
HashTable(StrC) tok_map;
|
||||
{
|
||||
tok_map = hashtable_init(StrC, fixed_arena_allocator_info(& tok_map_arena) );
|
||||
|
||||
s32 left = num_tokens - 1;
|
||||
|
||||
@@ -27,8 +25,7 @@ ssize token_fmt_va( char* buf, usize buf_size, s32 num_tokens, va_list va )
|
||||
StrC value = va_arg( va, StrC );
|
||||
|
||||
u32 key = crc32( token, str_len(token) );
|
||||
|
||||
tok_map.set( key, value );
|
||||
hashtable_set( tok_map, key, value );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +61,7 @@ ssize token_fmt_va( char* buf, usize buf_size, s32 num_tokens, va_list va )
|
||||
char const* token = fmt + 1;
|
||||
|
||||
u32 key = crc32( token, tok_len );
|
||||
StrC* value = tok_map.get( key );
|
||||
StrC* value = hashtable_get(tok_map, key );
|
||||
|
||||
if ( value )
|
||||
{
|
||||
@@ -94,8 +91,8 @@ ssize token_fmt_va( char* buf, usize buf_size, s32 num_tokens, va_list va )
|
||||
}
|
||||
}
|
||||
|
||||
tok_map.clear();
|
||||
tok_map_arena.free();
|
||||
hashtable_clear(tok_map);
|
||||
fixed_arena_free(& tok_map_arena);
|
||||
|
||||
ssize result = buf_size - remaining;
|
||||
|
||||
@@ -107,19 +104,19 @@ Code untyped_str( StrC content )
|
||||
if ( content.Len == 0 )
|
||||
{
|
||||
log_failure( "untyped_str: empty string" );
|
||||
return CodeInvalid;
|
||||
return InvalidCode;
|
||||
}
|
||||
|
||||
Code
|
||||
result = make_code();
|
||||
result->Name = get_cached_string( content );
|
||||
result->Type = ECode::Untyped;
|
||||
result->Type = CT_Untyped;
|
||||
result->Content = result->Name;
|
||||
|
||||
if ( result->Name == nullptr )
|
||||
{
|
||||
log_failure( "untyped_str: could not cache string" );
|
||||
return CodeInvalid;
|
||||
return InvalidCode;
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -130,7 +127,7 @@ Code untyped_fmt( char const* fmt, ...)
|
||||
if ( fmt == nullptr )
|
||||
{
|
||||
log_failure( "untyped_fmt: null format string" );
|
||||
return CodeInvalid;
|
||||
return InvalidCode;
|
||||
}
|
||||
|
||||
local_persist thread_local
|
||||
@@ -143,14 +140,14 @@ Code untyped_fmt( char const* fmt, ...)
|
||||
|
||||
Code
|
||||
result = make_code();
|
||||
result->Name = get_cached_string( { str_len(fmt, MaxNameLength), fmt } );
|
||||
result->Type = ECode::Untyped;
|
||||
result->Name = get_cached_string( { str_len_capped(fmt, MaxNameLength), fmt } );
|
||||
result->Type = CT_Untyped;
|
||||
result->Content = get_cached_string( { length, buf } );
|
||||
|
||||
if ( result->Name == nullptr )
|
||||
{
|
||||
log_failure( "untyped_fmt: could not cache string" );
|
||||
return CodeInvalid;
|
||||
return InvalidCode;
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -161,7 +158,7 @@ Code untyped_token_fmt( s32 num_tokens, ... )
|
||||
if ( num_tokens == 0 )
|
||||
{
|
||||
log_failure( "untyped_token_fmt: zero tokens" );
|
||||
return CodeInvalid;
|
||||
return InvalidCode;
|
||||
}
|
||||
|
||||
local_persist thread_local
|
||||
@@ -175,13 +172,13 @@ Code untyped_token_fmt( s32 num_tokens, ... )
|
||||
Code
|
||||
result = make_code();
|
||||
result->Name = get_cached_string( { length, buf } );
|
||||
result->Type = ECode::Untyped;
|
||||
result->Type = CT_Untyped;
|
||||
result->Content = result->Name;
|
||||
|
||||
if ( result->Name == nullptr )
|
||||
{
|
||||
log_failure( "untyped_fmt: could not cache string" );
|
||||
return CodeInvalid;
|
||||
return InvalidCode;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+514
-440
File diff suppressed because it is too large
Load Diff
+1653
-1449
File diff suppressed because it is too large
Load Diff
@@ -7,22 +7,22 @@
|
||||
|
||||
// TODO : Convert global allocation strategy to use a slab allocation strategy.
|
||||
global AllocatorInfo GlobalAllocator;
|
||||
global Array<Arena> Global_AllocatorBuckets;
|
||||
global Array( Arena ) Global_AllocatorBuckets;
|
||||
|
||||
// TODO(Ed) : Make the code pool a dynamic arena
|
||||
global Array< Pool > CodePools = { nullptr };
|
||||
global Array< Arena > StringArenas = { nullptr };
|
||||
global Array( Pool ) CodePools = { nullptr };
|
||||
global Array( Arena ) StringArenas = { nullptr };
|
||||
|
||||
global StringTable StringCache;
|
||||
|
||||
global Arena LexArena;
|
||||
|
||||
global AllocatorInfo Allocator_DataArrays = heap();
|
||||
global AllocatorInfo Allocator_CodePool = heap();
|
||||
global AllocatorInfo Allocator_Lexer = heap();
|
||||
global AllocatorInfo Allocator_StringArena = heap();
|
||||
global AllocatorInfo Allocator_StringTable = heap();
|
||||
global AllocatorInfo Allocator_TypeTable = heap();
|
||||
global AllocatorInfo Allocator_DataArrays = {0};
|
||||
global AllocatorInfo Allocator_CodePool = {0};
|
||||
global AllocatorInfo Allocator_Lexer = {0};
|
||||
global AllocatorInfo Allocator_StringArena = {0};
|
||||
global AllocatorInfo Allocator_StringTable = {0};
|
||||
global AllocatorInfo Allocator_TypeTable = {0};
|
||||
|
||||
#pragma endregion StaticData
|
||||
|
||||
@@ -72,36 +72,36 @@ global CodeSpecifiers spec_thread_local;
|
||||
global CodeSpecifiers spec_virtual;
|
||||
global CodeSpecifiers spec_volatile;
|
||||
|
||||
global CodeType t_empty;
|
||||
global CodeType t_auto;
|
||||
global CodeType t_void;
|
||||
global CodeType t_int;
|
||||
global CodeType t_bool;
|
||||
global CodeType t_char;
|
||||
global CodeType t_wchar_t;
|
||||
global CodeType t_class;
|
||||
global CodeType t_typename;
|
||||
global CodeTypename t_empty;
|
||||
global CodeTypename t_auto;
|
||||
global CodeTypename t_void;
|
||||
global CodeTypename t_int;
|
||||
global CodeTypename t_bool;
|
||||
global CodeTypename t_char;
|
||||
global CodeTypename t_wchar_t;
|
||||
global CodeTypename t_class;
|
||||
global CodeTypename t_typename;
|
||||
|
||||
global Array< StringCached > PreprocessorDefines;
|
||||
global Array(StringCached) PreprocessorDefines;
|
||||
|
||||
#ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS
|
||||
global CodeType t_b32;
|
||||
global CodeTypename t_b32;
|
||||
|
||||
global CodeType t_s8;
|
||||
global CodeType t_s16;
|
||||
global CodeType t_s32;
|
||||
global CodeType t_s64;
|
||||
global CodeTypename t_s8;
|
||||
global CodeTypename t_s16;
|
||||
global CodeTypename t_s32;
|
||||
global CodeTypename t_s64;
|
||||
|
||||
global CodeType t_u8;
|
||||
global CodeType t_u16;
|
||||
global CodeType t_u32;
|
||||
global CodeType t_u64;
|
||||
global CodeTypename t_u8;
|
||||
global CodeTypename t_u16;
|
||||
global CodeTypename t_u32;
|
||||
global CodeTypename t_u64;
|
||||
|
||||
global CodeType t_ssize;
|
||||
global CodeType t_usize;
|
||||
global CodeTypename t_ssize;
|
||||
global CodeTypename t_usize;
|
||||
|
||||
global CodeType t_f32;
|
||||
global CodeType t_f64;
|
||||
global CodeTypename t_f32;
|
||||
global CodeTypename t_f64;
|
||||
#endif
|
||||
|
||||
#pragma endregion Constants
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
#include "header_start.hpp"
|
||||
#endif
|
||||
|
||||
/*
|
||||
________ __ __ ________
|
||||
| \ | \ | \ | \
|
||||
| ▓▓▓▓▓▓▓▓_______ __ __ ______ ____ _______ | ▓▓\ | ▓▓ \▓▓▓▓▓▓▓▓__ __ ______ ______ _______
|
||||
| ▓▓__ | \| \ | \ \ \ / \ | ▓▓▓\| ▓▓ | ▓▓ | \ | \/ \ / \ / \
|
||||
| ▓▓ \ | ▓▓▓▓▓▓▓\ ▓▓ | ▓▓ ▓▓▓▓▓▓\▓▓▓▓\ ▓▓▓▓▓▓▓ | ▓▓▓▓\ ▓▓ | ▓▓ | ▓▓ | ▓▓ ▓▓▓▓▓▓\ ▓▓▓▓▓▓\ ▓▓▓▓▓▓▓
|
||||
| ▓▓▓▓▓ | ▓▓ | ▓▓ ▓▓ | ▓▓ ▓▓ | ▓▓ | ▓▓\▓▓ \ | ▓▓\▓▓ ▓▓ | ▓▓ | ▓▓ | ▓▓ ▓▓ | ▓▓ ▓▓ ▓▓\▓▓ \
|
||||
| ▓▓_____| ▓▓ | ▓▓ ▓▓__/ ▓▓ ▓▓ | ▓▓ | ▓▓_\▓▓▓▓▓▓\ | ▓▓ \▓▓▓▓ | ▓▓ | ▓▓__/ ▓▓ ▓▓__/ ▓▓ ▓▓▓▓▓▓▓▓_\▓▓▓▓▓▓\
|
||||
| ▓▓ \ ▓▓ | ▓▓\▓▓ ▓▓ ▓▓ | ▓▓ | ▓▓ ▓▓ | ▓▓ \▓▓▓ | ▓▓ \▓▓ ▓▓ ▓▓ ▓▓\▓▓ \ ▓▓
|
||||
\▓▓▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓▓▓ \▓▓ \▓▓ \▓▓\▓▓▓▓▓▓▓ \▓▓ \▓▓ \▓▓ _\▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓\▓▓▓▓▓▓▓
|
||||
| \__| ▓▓ ▓▓
|
||||
\▓▓ ▓▓ ▓▓
|
||||
\▓▓▓▓▓▓ \▓▓
|
||||
|
||||
*/
|
||||
|
||||
using LogFailType = ssize(*)(char const*, ...);
|
||||
|
||||
// By default this library will either crash or exit if an error is detected while generating codes.
|
||||
@@ -13,95 +29,110 @@ using LogFailType = ssize(*)(char const*, ...);
|
||||
#define log_failure GEN_FATAL
|
||||
#endif
|
||||
|
||||
enum class AccessSpec : u32
|
||||
enum AccessSpec : u32
|
||||
{
|
||||
Default,
|
||||
Private,
|
||||
Protected,
|
||||
Public,
|
||||
AccessSpec_Default,
|
||||
AccessSpec_Private,
|
||||
AccessSpec_Protected,
|
||||
AccessSpec_Public,
|
||||
|
||||
Num_AccessSpec,
|
||||
Invalid,
|
||||
AccessSpec_Num_AccessSpec,
|
||||
AccessSpec_Invalid,
|
||||
|
||||
AccessSpec_SizeDef = GEN_U32_MAX,
|
||||
};
|
||||
static_assert( size_of(AccessSpec) == size_of(u32), "AccessSpec not u32 size" );
|
||||
|
||||
inline
|
||||
char const* to_str( AccessSpec type )
|
||||
StrC access_spec_to_str( AccessSpec type )
|
||||
{
|
||||
local_persist
|
||||
char const* lookup[ (u32)AccessSpec::Num_AccessSpec ] = {
|
||||
"",
|
||||
"private",
|
||||
"protected",
|
||||
"public",
|
||||
StrC lookup[ (u32)AccessSpec_Num_AccessSpec ] = {
|
||||
{ sizeof("") - 1, "" },
|
||||
{ sizeof("prviate") - 1, "private" },
|
||||
{ sizeof("protected") - 1, "private" },
|
||||
{ sizeof("public") - 1, "public" },
|
||||
};
|
||||
|
||||
if ( type > AccessSpec::Public )
|
||||
return "Invalid";
|
||||
StrC invalid = { sizeof("Invalid") - 1, "Invalid" };
|
||||
if ( type > AccessSpec_Public )
|
||||
return invalid;
|
||||
|
||||
return lookup[ (u32)type ];
|
||||
}
|
||||
|
||||
|
||||
enum CodeFlag : u32
|
||||
{
|
||||
None = 0,
|
||||
FunctionType = bit(0),
|
||||
ParamPack = bit(1),
|
||||
Module_Export = bit(2),
|
||||
Module_Import = bit(3),
|
||||
CodeFlag_None = 0,
|
||||
CodeFlag_FunctionType = bit(0),
|
||||
CodeFlag_ParamPack = bit(1),
|
||||
CodeFlag_Module_Export = bit(2),
|
||||
CodeFlag_Module_Import = bit(3),
|
||||
|
||||
CodeFlag_SizeDef = GEN_U32_MAX,
|
||||
};
|
||||
static_assert( size_of(CodeFlag) == size_of(u32), "CodeFlag not u32 size" );
|
||||
|
||||
// Used to indicate if enum definitoin is an enum class or regular enum.
|
||||
enum class EnumT : u8
|
||||
enum EnumDecl : u8
|
||||
{
|
||||
Regular,
|
||||
Class
|
||||
EnumDecl_Regular,
|
||||
EnumDecl_Class,
|
||||
|
||||
EnumT_SizeDef = GEN_U8_MAX,
|
||||
};
|
||||
typedef u8 EnumT;
|
||||
|
||||
constexpr EnumT EnumClass = EnumT::Class;
|
||||
constexpr EnumT EnumRegular = EnumT::Regular;
|
||||
|
||||
enum class ModuleFlag : u32
|
||||
enum ModuleFlag : u32
|
||||
{
|
||||
None = 0,
|
||||
Export = bit(0),
|
||||
Import = bit(1),
|
||||
ModuleFlag_None = 0,
|
||||
ModuleFlag_Export = bit(0),
|
||||
ModuleFlag_Import = bit(1),
|
||||
|
||||
Num_ModuleFlags,
|
||||
Invalid,
|
||||
ModuleFlag_Invalid,
|
||||
|
||||
ModuleFlag_SizeDef = GEN_U32_MAX,
|
||||
};
|
||||
static_assert( size_of(ModuleFlag) == size_of(u32), "ModuleFlag not u32 size" );
|
||||
|
||||
inline
|
||||
StrC to_str( ModuleFlag flag )
|
||||
StrC module_flag_to_str( ModuleFlag flag )
|
||||
{
|
||||
local_persist
|
||||
StrC lookup[ (u32)ModuleFlag::Num_ModuleFlags ] = {
|
||||
StrC lookup[ (u32)Num_ModuleFlags ] = {
|
||||
{ sizeof("__none__"), "__none__" },
|
||||
{ sizeof("export"), "export" },
|
||||
{ sizeof("import"), "import" },
|
||||
};
|
||||
|
||||
if ( flag > ModuleFlag::Import )
|
||||
return { sizeof("invalid"), "invalid" };
|
||||
local_persist
|
||||
StrC invalid_flag = { sizeof("invalid"), "invalid" };
|
||||
if ( flag > ModuleFlag_Import )
|
||||
return invalid_flag;
|
||||
|
||||
return lookup[ (u32)flag ];
|
||||
}
|
||||
|
||||
inline
|
||||
ModuleFlag operator|( ModuleFlag A, ModuleFlag B)
|
||||
enum EPreprocessCond : u32
|
||||
{
|
||||
return (ModuleFlag)( (u32)A | (u32)B );
|
||||
}
|
||||
PreprocessCond_If,
|
||||
PreprocessCond_IfDef,
|
||||
PreprocessCond_IfNotDef,
|
||||
PreprocessCond_ElIf,
|
||||
|
||||
enum class EPreprocessCond : u32
|
||||
{
|
||||
If,
|
||||
IfDef,
|
||||
IfNotDef,
|
||||
ElIf
|
||||
EPreprocessCond_SizeDef = GEN_U32_MAX,
|
||||
};
|
||||
static_assert( size_of(EPreprocessCond) == size_of(u32), "EPreprocessCond not u32 size" );
|
||||
|
||||
constexpr EPreprocessCond PreprocessCond_If = EPreprocessCond::If;
|
||||
constexpr EPreprocessCond PreprocessCond_IfDef = EPreprocessCond::IfDef;
|
||||
constexpr EPreprocessCond PreprocessCond_IfNotDef = EPreprocessCond::IfNotDef;
|
||||
constexpr EPreprocessCond PreprocessCond_ElIf = EPreprocessCond::ElIf;
|
||||
enum ETypenameTag : u16
|
||||
{
|
||||
Tag_None,
|
||||
Tag_Class,
|
||||
Tag_Enum,
|
||||
Tag_Struct,
|
||||
Tag_Union,
|
||||
|
||||
Tag_UnderlyingType = GEN_U16_MAX,
|
||||
};
|
||||
static_assert( size_of(ETypenameTag) == size_of(u16), "ETypenameTag is not u16 size");
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
# pragma once
|
||||
# include "platform.hpp"
|
||||
# include "macros.hpp"
|
||||
#endif
|
||||
|
||||
@@ -122,13 +123,21 @@ typedef s8 b8;
|
||||
typedef s16 b16;
|
||||
typedef s32 b32;
|
||||
|
||||
using mem_ptr = void*;
|
||||
using mem_ptr_const = void const*;
|
||||
typedef void* mem_ptr;
|
||||
typedef void const* mem_ptr_const ;
|
||||
|
||||
#if GEN_COMPILER_CPP
|
||||
template<typename Type> uptr to_uptr( Type* ptr ) { return (uptr)ptr; }
|
||||
template<typename Type> sptr to_sptr( Type* ptr ) { return (sptr)ptr; }
|
||||
|
||||
template<typename Type> mem_ptr to_mem_ptr ( Type ptr ) { return (mem_ptr) ptr; }
|
||||
template<typename Type> mem_ptr_const to_mem_ptr_const( Type ptr ) { return (mem_ptr_const)ptr; }
|
||||
#else
|
||||
#define to_uptr( ptr ) ((uptr)(ptr))
|
||||
#define to_sptr( ptr ) ((sptr)(ptr))
|
||||
|
||||
#define to_mem_ptr( ptr) ((mem_ptr)ptr)
|
||||
#define to_mem_ptr_const( ptr) ((mem_ptr)ptr)
|
||||
#endif
|
||||
|
||||
#pragma endregion Basic Types
|
||||
|
||||
+503
-257
File diff suppressed because it is too large
Load Diff
@@ -7,9 +7,9 @@
|
||||
|
||||
#pragma region Debug
|
||||
|
||||
void assert_handler( char const* condition, char const* file, s32 line, char const* msg, ... )
|
||||
void assert_handler( char const* condition, char const* file, char const* function, s32 line, char const* msg, ... )
|
||||
{
|
||||
_printf_err( "%s:(%d): Assert Failure: ", file, line );
|
||||
_printf_err( "%s - %s:(%d): Assert Failure: ", file, function, line );
|
||||
|
||||
if ( condition )
|
||||
_printf_err( "`%s` \n", condition );
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
{ \
|
||||
if ( ! ( cond ) ) \
|
||||
{ \
|
||||
assert_handler( #cond, __FILE__, scast( s64, __LINE__ ), msg, ##__VA_ARGS__ ); \
|
||||
assert_handler( #cond, __FILE__, __func__, scast( s64, __LINE__ ), msg, ##__VA_ARGS__ ); \
|
||||
GEN_DEBUG_TRAP(); \
|
||||
} \
|
||||
} while ( 0 )
|
||||
@@ -56,7 +56,7 @@
|
||||
while (0)
|
||||
#endif
|
||||
|
||||
void assert_handler( char const* condition, char const* file, s32 line, char const* msg, ... );
|
||||
void assert_handler( char const* condition, char const* file, char const* function, s32 line, char const* msg, ... );
|
||||
s32 assert_crash( char const* condition );
|
||||
void process_exit( u32 code );
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ wchar_t* _alloc_utf8_to_ucs2( AllocatorInfo a, char const* text, ssize* w_len_ )
|
||||
w_len1 = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, text, scast( int, len), w_text, scast( int, w_len) );
|
||||
if ( w_len1 == 0 )
|
||||
{
|
||||
free( a, w_text );
|
||||
allocator_free( a, w_text );
|
||||
if ( w_len_ )
|
||||
*w_len_ = 0;
|
||||
return NULL;
|
||||
@@ -145,7 +145,7 @@ GEN_FILE_OPEN_PROC( _win32_file_open )
|
||||
w_text = _alloc_utf8_to_ucs2( heap(), filename, NULL );
|
||||
handle = CreateFileW( w_text, desired_access, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, creation_disposition, FILE_ATTRIBUTE_NORMAL, NULL );
|
||||
|
||||
free( heap(), w_text );
|
||||
allocator_free( heap(), w_text );
|
||||
|
||||
if ( handle == INVALID_HANDLE_VALUE )
|
||||
{
|
||||
@@ -340,7 +340,7 @@ FileError file_close( FileInfo* f )
|
||||
return EFileError_INVALID;
|
||||
|
||||
if ( f->filename )
|
||||
free( heap(), ccast( char*, f->filename ));
|
||||
allocator_free( heap(), ccast( char*, f->filename ));
|
||||
|
||||
#if defined( GEN_SYSTEM_WINDOWS )
|
||||
if ( f->fd.p == INVALID_HANDLE_VALUE )
|
||||
@@ -459,6 +459,7 @@ FileContents file_read_contents( AllocatorInfo a, b32 zero_terminate, char const
|
||||
return result;
|
||||
}
|
||||
|
||||
typedef struct _memory_fd _memory_fd;
|
||||
struct _memory_fd
|
||||
{
|
||||
u8 magic;
|
||||
@@ -505,7 +506,7 @@ b8 file_stream_new( FileInfo* file, AllocatorInfo allocator )
|
||||
d->allocator = allocator;
|
||||
d->flags = EFileStream_CLONE_WRITABLE;
|
||||
d->cap = 0;
|
||||
d->buf = Array<u8>::init( allocator );
|
||||
d->buf = array_init( u8, allocator );
|
||||
|
||||
if ( ! d->buf )
|
||||
return false;
|
||||
@@ -531,7 +532,7 @@ b8 file_stream_open( FileInfo* file, AllocatorInfo allocator, u8* buffer, ssize
|
||||
d->flags = flags;
|
||||
if ( d->flags & EFileStream_CLONE_WRITABLE )
|
||||
{
|
||||
Array<u8> arr = Array<u8>::init_reserve( allocator, size );
|
||||
Array(u8) arr = array_init_reserve(u8, allocator, size );
|
||||
d->buf = arr;
|
||||
|
||||
if ( ! d->buf )
|
||||
@@ -540,7 +541,7 @@ b8 file_stream_open( FileInfo* file, AllocatorInfo allocator, u8* buffer, ssize
|
||||
mem_copy( d->buf, buffer, size );
|
||||
d->cap = size;
|
||||
|
||||
arr.get_header()->Num = size;
|
||||
array_get_header(arr)->Num = size;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -608,11 +609,11 @@ GEN_FILE_WRITE_AT_PROC( _memory_file_write )
|
||||
|
||||
if ( d->flags & EFileStream_CLONE_WRITABLE )
|
||||
{
|
||||
Array<u8> arr = { d->buf };
|
||||
Array(u8) arr = { d->buf };
|
||||
|
||||
if ( arr.get_header()->Capacity < usize(new_cap) )
|
||||
if ( array_get_header(arr)->Capacity < scast(usize, new_cap) )
|
||||
{
|
||||
if ( ! arr.grow( ( s64 )( new_cap ) ) )
|
||||
if ( ! array_grow( & arr, ( s64 )( new_cap ) ) )
|
||||
return false;
|
||||
d->buf = arr;
|
||||
}
|
||||
@@ -622,11 +623,11 @@ GEN_FILE_WRITE_AT_PROC( _memory_file_write )
|
||||
|
||||
if ( ( d->flags & EFileStream_CLONE_WRITABLE ) && extralen > 0 )
|
||||
{
|
||||
Array<u8> arr = { d->buf };
|
||||
Array(u8) arr = { d->buf };
|
||||
|
||||
mem_copy( d->buf + offset + rwlen, pointer_add_const( buffer, rwlen ), extralen );
|
||||
d->cap = new_cap;
|
||||
arr.get_header()->Capacity = new_cap;
|
||||
array_get_header(arr)->Capacity = new_cap;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -646,11 +647,11 @@ GEN_FILE_CLOSE_PROC( _memory_file_close )
|
||||
|
||||
if ( d->flags & EFileStream_CLONE_WRITABLE )
|
||||
{
|
||||
Array<u8> arr = { d->buf };
|
||||
arr.free();
|
||||
Array(u8) arr = { d->buf };
|
||||
array_free(arr);
|
||||
}
|
||||
|
||||
free( allocator, d );
|
||||
allocator_free( allocator, d );
|
||||
}
|
||||
|
||||
FileOperations const memory_file_operations = { _memory_file_read, _memory_file_write, _memory_file_seek, _memory_file_close };
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
|
||||
#pragma region File Handling
|
||||
|
||||
typedef u32 FileMode;
|
||||
|
||||
enum FileModeFlag
|
||||
{
|
||||
EFileMode_READ = bit( 0 ),
|
||||
@@ -45,11 +43,12 @@ union FileDescriptor
|
||||
uptr u;
|
||||
};
|
||||
|
||||
typedef u32 FileMode;
|
||||
typedef struct FileOperations FileOperations;
|
||||
|
||||
#define GEN_FILE_OPEN_PROC( name ) FileError name( FileDescriptor* fd, FileOperations* ops, FileMode mode, char const* filename )
|
||||
#define GEN_FILE_READ_AT_PROC( name ) b32 name( FileDescriptor fd, void* buffer, ssize size, s64 offset, ssize* bytes_read, b32 stop_at_newline )
|
||||
#define GEN_FILE_WRITE_AT_PROC( name ) b32 name( FileDescriptor fd, void const* buffer, ssize size, s64 offset, ssize* bytes_written )
|
||||
#define GEN_FILE_WRITE_AT_PROC( name ) b32 name( FileDescriptor fd, mem_ptr_const buffer, ssize size, s64 offset, ssize* bytes_written )
|
||||
#define GEN_FILE_SEEK_PROC( name ) b32 name( FileDescriptor fd, s64 offset, SeekWhenceType whence, s64* new_offset )
|
||||
#define GEN_FILE_CLOSE_PROC( name ) void name( FileDescriptor fd )
|
||||
|
||||
@@ -83,7 +82,7 @@ struct DirInfo;
|
||||
struct DirEntry
|
||||
{
|
||||
char const* filename;
|
||||
struct DirInfo* dir_info;
|
||||
DirInfo* dir_info;
|
||||
u8 type;
|
||||
};
|
||||
|
||||
@@ -183,6 +182,7 @@ b32 file_read_at( FileInfo* file, void* buffer, ssize size, s64 offset );
|
||||
*/
|
||||
b32 file_read_at_check( FileInfo* file, void* buffer, ssize size, s64 offset, ssize* bytes_read );
|
||||
|
||||
typedef struct FileContents FileContents;
|
||||
struct FileContents
|
||||
{
|
||||
AllocatorInfo allocator;
|
||||
@@ -190,8 +190,8 @@ struct FileContents
|
||||
ssize size;
|
||||
};
|
||||
|
||||
constexpr b32 zero_terminate = true;
|
||||
constexpr b32 no_zero_terminate = false;
|
||||
constexpr b32 file_zero_terminate = true;
|
||||
constexpr b32 file_no_zero_terminate = false;
|
||||
|
||||
/**
|
||||
* Reads the whole file contents
|
||||
@@ -265,6 +265,8 @@ enum FileStreamFlags : u32
|
||||
/* Clones the input buffer so you can write (zpl_file_write*) data into it. */
|
||||
/* Since we work with a clone, the buffer size can dynamically grow as well. */
|
||||
EFileStream_CLONE_WRITABLE = bit( 1 ),
|
||||
|
||||
EFileStream_UNDERLYING = GEN_U32_MAX,
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
+246
-12
@@ -14,15 +14,27 @@
|
||||
#define local_persist static // Local Persisting variables
|
||||
#endif
|
||||
|
||||
#ifndef api_c
|
||||
#define api_c extern "C"
|
||||
#endif
|
||||
|
||||
#ifndef bit
|
||||
#define bit( Value ) ( 1 << Value )
|
||||
#define bitfield_is_equal( Type, Field, Mask ) ( (Type(Mask) & Type(Field)) == Type(Mask) )
|
||||
#define bitfield_is_equal( Type, Field, Mask ) ( (scast(Type, Mask) & scast(Type, Field)) == scast(Type, Mask) )
|
||||
#endif
|
||||
|
||||
// Mainly intended for forcing the base library to utilize only C-valid constructs or type coercion
|
||||
#ifndef GEN_C_LIKE_CPP
|
||||
#define GEN_C_LIKE_CPP 0
|
||||
#endif
|
||||
|
||||
#if GEN_COMPILER_CPP
|
||||
# ifndef cast
|
||||
# define cast( type, value ) (tmpl_cast<type>( value ))
|
||||
# endif
|
||||
#else
|
||||
# ifndef cast
|
||||
# define cast( type, value ) ( (type)(value) )
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if GEN_COMPILER_CPP
|
||||
# ifndef ccast
|
||||
# define ccast( type, value ) ( const_cast< type >( (value) ) )
|
||||
# endif
|
||||
@@ -35,6 +47,20 @@
|
||||
# ifndef scast
|
||||
# define scast( type, value ) static_cast< type >( value )
|
||||
# endif
|
||||
#else
|
||||
# ifndef ccast
|
||||
# define ccast( type, value ) ( (type)(value) )
|
||||
# endif
|
||||
# ifndef pcast
|
||||
# define pcast( type, value ) ( * (type*)(& value) )
|
||||
# endif
|
||||
# ifndef rcast
|
||||
# define rcast( type, value ) ( (type)(value) )
|
||||
# endif
|
||||
# ifndef scast
|
||||
# define scast( type, value ) ( (type)(value) )
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef stringize
|
||||
#define stringize_va( ... ) #__VA_ARGS__
|
||||
@@ -72,6 +98,10 @@
|
||||
#endif
|
||||
|
||||
#ifndef num_args_impl
|
||||
|
||||
// This is essentially an arg couneter version of GEN_SELECT_ARG macros
|
||||
// See section : _Generic function overloading for that usage (explains this heavier case)
|
||||
|
||||
#define num_args_impl( _0, \
|
||||
_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \
|
||||
_11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \
|
||||
@@ -123,20 +153,20 @@
|
||||
#define min( a, b ) ( (a < b) ? (a) : (b) )
|
||||
#endif
|
||||
|
||||
#if defined( _MSC_VER ) || defined( GEN_COMPILER_TINYC )
|
||||
#if GEN_COMPILER_MSVC || GEN_COMPILER_TINYC
|
||||
# define offset_of( Type, element ) ( ( GEN_NS( ssize ) ) & ( ( ( Type* )0 )->element ) )
|
||||
#else
|
||||
# define offset_of( Type, element ) __builtin_offsetof( Type, element )
|
||||
#endif
|
||||
|
||||
#ifndef forceinline
|
||||
# ifdef GEN_COMPILER_MSVC
|
||||
# if GEN_COMPILER_MSVC
|
||||
# define forceinline __forceinline
|
||||
# define neverinline __declspec( noinline )
|
||||
# elif defined(GEN_COMPILER_GCC)
|
||||
# elif GEN_COMPILER_GCC
|
||||
# define forceinline inline __attribute__((__always_inline__))
|
||||
# define neverinline __attribute__( ( __noinline__ ) )
|
||||
# elif defined(GEN_COMPILER_CLANG)
|
||||
# elif GEN_COMPILER_CLANG
|
||||
# if __has_attribute(__always_inline__)
|
||||
# define forceinline inline __attribute__((__always_inline__))
|
||||
# define neverinline __attribute__( ( __noinline__ ) )
|
||||
@@ -151,11 +181,11 @@
|
||||
#endif
|
||||
|
||||
#ifndef neverinline
|
||||
# ifdef GEN_COMPILER_MSVC
|
||||
# if GEN_COMPILER_MSVC
|
||||
# define neverinline __declspec( noinline )
|
||||
# elif defined(GEN_COMPILER_GCC)
|
||||
# elif GEN_COMPILER_GCC
|
||||
# define neverinline __attribute__( ( __noinline__ ) )
|
||||
# elif defined(GEN_COMPILER_CLANG)
|
||||
# elif GEN_COMPILER_CLANG
|
||||
# if __has_attribute(__always_inline__)
|
||||
# define neverinline __attribute__( ( __noinline__ ) )
|
||||
# else
|
||||
@@ -166,4 +196,208 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if GEN_COMPILER_C
|
||||
#ifndef static_assert
|
||||
#undef static_assert
|
||||
#if GEN_COMPILER_C && __STDC_VERSION__ >= 201112L
|
||||
#define static_assert(condition, message) _Static_assert(condition, message)
|
||||
#else
|
||||
#define static_assert(condition, message) typedef char static_assertion_##__LINE__[(condition)?1:-1]
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if GEN_COMPILER_CPP
|
||||
// Already Defined
|
||||
#elif GEN_COMPILER_C && __STDC_VERSION__ >= 201112L
|
||||
# define thread_local _Thread_local
|
||||
#elif GEN_COMPILER_MSVC
|
||||
# define thread_local __declspec(thread)
|
||||
#elif GEN_COMPILER_CLANG
|
||||
# define thread_local __thread
|
||||
#else
|
||||
# error "No thread local support"
|
||||
#endif
|
||||
|
||||
#if ! defined(typeof) && (!GEN_COMPILER_C || __STDC_VERSION__ < 202311L)
|
||||
# if ! GEN_COMPILER_C
|
||||
# define typeof decltype
|
||||
# elif defined(_MSC_VER)
|
||||
# define typeof(x) __typeof__(x)
|
||||
# elif defined(__GNUC__) || defined(__clang__)
|
||||
# define typeof(x) __typeof__(x)
|
||||
# else
|
||||
# error "Compiler not supported"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef GEN_API_C_BEGIN
|
||||
# if GEN_COMPILER_C
|
||||
# define GEN_API_C_BEGIN
|
||||
# define GEN_API_C_END
|
||||
# else
|
||||
# define GEN_API_C_BEGIN extern "C" {
|
||||
# define GEN_API_C_END }
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if GEN_COMPILER_C
|
||||
# if __STDC_VERSION__ >= 202311L
|
||||
# define enum_underlying(type) : type
|
||||
# else
|
||||
# define enum_underlying(type)
|
||||
# endif
|
||||
#else
|
||||
# define enum_underlying(type) : type
|
||||
#endif
|
||||
|
||||
#if GEN_COMPILER_C
|
||||
# ifndef nullptr
|
||||
# define nullptr NULL
|
||||
# endif
|
||||
|
||||
# ifndef GEN_REMOVE_PTR
|
||||
# define GEN_REMOVE_PTR(type) typeof(* ( (type) NULL) )
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if ! defined(GEN_PARAM_DEFAULT) && GEN_COMPILER_CPP
|
||||
# define GEN_PARAM_DEFAULT = {}
|
||||
#else
|
||||
# define GEN_PARAM_DEFAULT
|
||||
#endif
|
||||
|
||||
#if GEN_COMPILER_CPP
|
||||
#define struct_init(type, value) {value}
|
||||
#else
|
||||
#define struct_init(type, value) {value}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#ifndef GEN_OPTIMIZE_MAPPINGS_BEGIN
|
||||
# define GEN_OPTIMIZE_MAPPINGS_BEGIN _pragma(optimize("gt", on))
|
||||
# define GEN_OPITMIZE_MAPPINGS_END _pragma(optimize("", on))
|
||||
#endif
|
||||
#else
|
||||
# define GEN_OPTIMIZE_MAPPINGS_BEGIN
|
||||
# define GEN_OPITMIZE_MAPPINGS_END
|
||||
#endif
|
||||
|
||||
#if GEN_COMPILER_C
|
||||
// ____ _ ______ _ _ ____ _ __ _
|
||||
// / ___} (_) | ____} | | (_) / __ \ | | | |(_)
|
||||
// | | ___ ___ _ __ ___ _ __ _ ___ | |__ _ _ _ __ ___| |_ _ ___ _ __ | | | |_ _____ _ __ | | ___ __ _ __| | _ _ __ __ _
|
||||
// | |{__ |/ _ \ '_ \ / _ \ '__} |/ __| | __} | | | '_ \ / __} __} |/ _ \| '_ \ | | | \ \ / / _ \ '_ \| |/ _ \ / _` |/ _` || | '_ \ / _` |
|
||||
// | |__j | __/ | | | __/ | | | (__ | | | |_| | | | | (__| l_| | (_) | | | | | l__| |\ V / __/ | | | | (_) | (_| | (_| || | | | | (_| |
|
||||
// \____/ \___}_l l_l\___}_l l_l\___| l_l \__,_l_l l_l\___}\__}_l\___/l_l l_l \____/ \_/ \___}_l l_l_l\___/ \__,_l\__,_l|_|_| |_|\__, |
|
||||
// This implemnents macros for utilizing "The Naive Extendible _Generic Macro" explained in: __| |
|
||||
// https://github.com/JacksonAllan/CC/blob/main/articles/Better_C_Generics_Part_1_The_Extendible_Generic.md {___/
|
||||
// Since gencpp is used to generate the c-library, it was choosen over the more novel implementations to keep the macros as easy to understand and unobfuscated as possible.
|
||||
|
||||
#define GEN_COMMA_OPERATOR , // The comma operator is used by preprocessor macros to delimit arguments, so we have to represent it via a macro to prevent parsing incorrectly.
|
||||
|
||||
// Helper macros for argument selection
|
||||
#define GEN_SELECT_ARG_1( _1, ... ) _1 // <-- Of all th args passed pick _1.
|
||||
#define GEN_SELECT_ARG_2( _1, _2, ... ) _2 // <-- Of all the args passed pick _2.
|
||||
#define GEN_SELECT_ARG_3( _1, _2, _3, ... ) _3 // etc..
|
||||
|
||||
#define GEN_GENERIC_SEL_ENTRY_TYPE GEN_SELECT_ARG_1 // Use the arg expansion macro to select arg 1 which should have the type.
|
||||
#define GEN_GENERIC_SEL_ENTRY_FUNCTION GEN_SELECT_ARG_2 // Use the arg expansion macro to select arg 2 which should have the function.
|
||||
#define GEN_GENERIC_SEL_ENTRY_COMMA_DELIMITER GEN_SELECT_ARG_3 // Use the arg expansion macro to select arg 3 which should have the comma delimiter ','.
|
||||
|
||||
#define GEN_RESOLVED_FUNCTION_CALL // Just used to indicate where the call "occurs"
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------------------------------------
|
||||
// GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( macro ) includes a _Generic slot only if the specified macro is defined (as type, function_name).
|
||||
// It takes advantage of the fact that if the macro is defined, then the expanded text will contain a comma.
|
||||
// Expands to ',' if it can find (type): (function) <comma_operator: ',' >
|
||||
// Where GEN_GENERIC_SEL_ENTRY_COMMA_DELIMITER is specifically looking for that <comma> ,
|
||||
#define GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( slot_exp ) GEN_GENERIC_SEL_ENTRY_COMMA_DELIMITER( slot_exp, GEN_GENERIC_SEL_ENTRY_TYPE( slot_exp, ): GEN_GENERIC_SEL_ENTRY_FUNCTION( slot_exp, ) GEN_COMMA_OPERATOR, , )
|
||||
// ^ Selects the comma ^ is the type ^ is the function ^ Insert a comma
|
||||
// The slot won't exist if that comma is not found. |
|
||||
|
||||
// For the occastion where an expression didn't resolve to a selection option the "default: <value>" wilbe set to:
|
||||
typedef struct GENCPP_NO_RESOLVED_GENERIC_SELECTION GENCPP_NO_RESOLVED_GENERIC_SELECTION;
|
||||
struct GENCPP_NO_RESOLVED_GENERIC_SELECTION {
|
||||
void* _THE_VOID_SLOT_;
|
||||
};
|
||||
GENCPP_NO_RESOLVED_GENERIC_SELECTION const gen_generic_selection_fail = {0};
|
||||
// Which will provide the message: error: called object type 'struct NO_RESOLVED_GENERIC_SELECTION' is not a function or function pointer
|
||||
// ----------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Below are generated on demand for an overlaod depdendent on a type:
|
||||
// -----------------------------------------------------------------------------------------------------#define GEN_FUNCTION_GENERIC_EXAMPLE( selector_arg ) _Generic( k
|
||||
#define GEN_FUNCTION_GENERIC_EXAMPLE( selector_arg ) _Generic( \
|
||||
(selector_arg), /* Select Via Expression*/ \
|
||||
/* Extendibility slots: */ \
|
||||
GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( FunctionID__ARGS_SIG_1 ) \
|
||||
GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( FunctionID__ARGS_SIG_1 ) \
|
||||
default: gen_generic_selection_fail \
|
||||
) GEN_RESOLVED_FUNCTION_CALL( selector_arg )
|
||||
// ----------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Then each definiton of a function has an associated define:
|
||||
// #define <function_id_macro> GEN_GENERIC_FUNCTION_ARG_SIGNATURE( <function_id>, <arguments> )
|
||||
#define GEN_GENERIC_FUNCTION_ARG_SIGNATURE( name_of_function, type_delimiter ) type_delimiter name_of_function
|
||||
|
||||
// Then somehwere later on
|
||||
// <etc> <return_type> <function_id> ( <arguments> ) { <implementation> }
|
||||
|
||||
// Concrete example:
|
||||
|
||||
// To add support for long:
|
||||
#define GEN_EXAMPLE_HASH__ARGS_SIG_1 GEN_GENERIC_FUNCTION_ARG_SIGNATURE( hash__P_long, long long )
|
||||
size_t gen_example_hash__P_long( long val ) { return val * 2654435761ull; }
|
||||
|
||||
// To add support for long long:
|
||||
#define GEN_EXAMPLE_HASH__ARGS_SIG_2 GEN_GENERIC_FUNCTION_ARG_SIGNATURE( hash__P_long_long, long long )
|
||||
size_t gen_example_hash__P_long_long( long long val ) { return val * 2654435761ull; }
|
||||
|
||||
// If using an Editor with support for syntax hightlighting macros: HASH__ARGS_SIG_1 and HASH_ARGS_SIG_2 should show color highlighting indicating the slot is enabled,
|
||||
// or, "defined" for usage during the compilation pass that handles the _Generic instrinsic.
|
||||
#define hash( function_arguments ) _Generic( \
|
||||
(function_arguments), /* Select Via Expression*/ \
|
||||
/* Extendibility slots: */ \
|
||||
GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( HASH__ARGS_SIG_1 ) \
|
||||
GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( HASH__ARGS_SIG_2 ) \
|
||||
GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( HASH__ARGS_SIG_3 ) \
|
||||
GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( HASH__ARGS_SIG_4 ) \
|
||||
GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( HASH__ARGS_SIG_5 ) \
|
||||
GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( HASH__ARGS_SIG_6 ) \
|
||||
GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( HASH__ARGS_SIG_7 ) \
|
||||
GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( HASH__ARGS_SIG_8 ) \
|
||||
default: gen_generic_selection_fail \
|
||||
) GEN_RESOLVED_FUNCTION_CALL( function_arguments )
|
||||
|
||||
// Additional Variations:
|
||||
|
||||
// If the function takes more than one argument the following is used:
|
||||
#define GEN_FUNCTION_GENERIC_EXAMPLE_VARADIC( selector_arg, ... ) _Generic( \
|
||||
(selector_arg), \
|
||||
GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( FunctionID__ARGS_SIG_1 ) \
|
||||
GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( FunctionID__ARGS_SIG_2 ) \
|
||||
/* ... */ \
|
||||
GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT(FunctionID__ARGS_SIG_N ) \
|
||||
default: gen_generic_selection_fail \
|
||||
) GEN_RESOLVED_FUNCTION_CALL( selector_arg, __VA_ARG__ )
|
||||
|
||||
// If the function does not take the arugment as a parameter:
|
||||
#define GEN_FUNCTION_GENERIC_EXAMPLE_DIRECT_TYPE( selector_arg ) _Generic( \
|
||||
( GEN_TYPE_TO_EXP(selector_arg) ), \
|
||||
GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( FunctionID__ARGS_SIG_1 ) \
|
||||
GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( FunctionID__ARGS_SIG_2 ) \
|
||||
/* ... */ \
|
||||
GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT(FunctionID__ARGS_SIG_N ) \
|
||||
default: gen_generic_selection_fail \
|
||||
) GEN_RESOLVED_FUNCTION_CALL()
|
||||
|
||||
// Used to keep the _Generic keyword happy as bare types are not considered "expressions"
|
||||
#define GEN_TYPE_TO_EXP(type) (* (type*)NULL)
|
||||
|
||||
// typedef void* GEN_GenericExampleType;
|
||||
// GEN_FUNCTION_GENERIC_EXAMPLE_DIRECT_TYPE( GEN_GenericExampleType );
|
||||
|
||||
// END OF ------------------------ _Generic function overloading ----------------------------------------- END OF
|
||||
#endif
|
||||
|
||||
#pragma endregion Macros
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
|
||||
void* mem_copy( void* dest, void const* source, ssize n )
|
||||
{
|
||||
if ( dest == NULL )
|
||||
if ( dest == nullptr )
|
||||
{
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return memcpy( dest, source, n );
|
||||
@@ -46,6 +46,7 @@ void const* mem_find( void const* data, u8 c, ssize n )
|
||||
|
||||
#define GEN_HEAP_STATS_MAGIC 0xDEADC0DE
|
||||
|
||||
typedef struct _heap_stats _heap_stats;
|
||||
struct _heap_stats
|
||||
{
|
||||
u32 magic;
|
||||
@@ -80,6 +81,7 @@ void heap_stats_check( void )
|
||||
GEN_ASSERT( _heap_stats_info.alloc_count == 0 );
|
||||
}
|
||||
|
||||
typedef struct _heap_alloc_info _heap_alloc_info;
|
||||
struct _heap_alloc_info
|
||||
{
|
||||
ssize size;
|
||||
@@ -334,7 +336,7 @@ ssize virtual_memory_page_size( ssize* alignment_out )
|
||||
|
||||
#pragma endregion VirtualMemory
|
||||
|
||||
void* Arena::allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags )
|
||||
void* arena_allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags )
|
||||
{
|
||||
Arena* arena = rcast(Arena*, allocator_data);
|
||||
void* ptr = NULL;
|
||||
@@ -346,7 +348,7 @@ void* Arena::allocator_proc( void* allocator_data, AllocType type, ssize size, s
|
||||
case EAllocation_ALLOC :
|
||||
{
|
||||
void* end = pointer_add( arena->PhysicalStart, arena->TotalUsed );
|
||||
ssize total_size = align_forward_i64( size, alignment );
|
||||
ssize total_size = align_forward_s64( size, alignment );
|
||||
|
||||
// NOTE: Out of memory
|
||||
if ( arena->TotalUsed + total_size > (ssize) arena->TotalSize )
|
||||
@@ -384,7 +386,7 @@ void* Arena::allocator_proc( void* allocator_data, AllocType type, ssize size, s
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void* Pool::allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags )
|
||||
void* pool_allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags )
|
||||
{
|
||||
Pool* pool = rcast( Pool*, allocator_data);
|
||||
void* ptr = NULL;
|
||||
@@ -457,7 +459,7 @@ void* Pool::allocator_proc( void* allocator_data, AllocType type, ssize size, ss
|
||||
return ptr;
|
||||
}
|
||||
|
||||
Pool Pool::init_align( AllocatorInfo backing, ssize num_blocks, ssize block_size, ssize block_align )
|
||||
Pool pool_init_align( AllocatorInfo backing, ssize num_blocks, ssize block_size, ssize block_align )
|
||||
{
|
||||
Pool pool = {};
|
||||
|
||||
@@ -495,16 +497,16 @@ Pool Pool::init_align( AllocatorInfo backing, ssize num_blocks, ssize block_size
|
||||
return pool;
|
||||
}
|
||||
|
||||
void Pool::clear()
|
||||
void pool_clear(Pool* pool)
|
||||
{
|
||||
ssize actual_block_size, block_index;
|
||||
void* curr;
|
||||
uptr* end;
|
||||
|
||||
actual_block_size = BlockSize + BlockAlign;
|
||||
actual_block_size = pool->BlockSize + pool->BlockAlign;
|
||||
|
||||
curr = PhysicalStart;
|
||||
for ( block_index = 0; block_index < NumBlocks - 1; block_index++ )
|
||||
curr = pool->PhysicalStart;
|
||||
for ( block_index = 0; block_index < pool->NumBlocks - 1; block_index++ )
|
||||
{
|
||||
uptr* next = ( uptr* ) curr;
|
||||
*next = ( uptr ) curr + actual_block_size;
|
||||
@@ -514,7 +516,7 @@ void Pool::clear()
|
||||
end = ( uptr* ) curr;
|
||||
*end = ( uptr ) NULL;
|
||||
|
||||
FreeList = PhysicalStart;
|
||||
pool->FreeList = pool->PhysicalStart;
|
||||
}
|
||||
|
||||
#pragma endregion Memory
|
||||
|
||||
+209
-108
@@ -29,7 +29,7 @@ b32 is_power_of_two( ssize x );
|
||||
void* align_forward( void* ptr, ssize alignment );
|
||||
|
||||
//! Aligns value to a specified alignment.
|
||||
s64 align_forward_i64( s64 value, ssize alignment );
|
||||
s64 align_forward_by_value( s64 value, ssize alignment );
|
||||
|
||||
//! Moves pointer forward by bytes.
|
||||
void* pointer_add( void* ptr, ssize bytes );
|
||||
@@ -70,10 +70,7 @@ enum AllocType : u8
|
||||
EAllocation_RESIZE,
|
||||
};
|
||||
|
||||
using AllocatorProc = void* ( void* allocator_data, AllocType type
|
||||
, ssize size, ssize alignment
|
||||
, void* old_memory, ssize old_size
|
||||
, u64 flags );
|
||||
typedef void*(AllocatorProc)( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags );
|
||||
|
||||
struct AllocatorInfo
|
||||
{
|
||||
@@ -101,7 +98,7 @@ void* alloc( AllocatorInfo a, ssize size );
|
||||
void* alloc_align( AllocatorInfo a, ssize size, ssize alignment );
|
||||
|
||||
//! Free allocated memory.
|
||||
void free( AllocatorInfo a, void* ptr );
|
||||
void allocator_free( AllocatorInfo a, void* ptr );
|
||||
|
||||
//! Free all memory allocated by an allocator.
|
||||
void free_all( AllocatorInfo a );
|
||||
@@ -135,7 +132,7 @@ void* default_resize_align( AllocatorInfo a, void* ptr, ssize old_size, ssize ne
|
||||
void* heap_allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags );
|
||||
|
||||
//! The heap allocator backed by operating system's memory manager.
|
||||
constexpr AllocatorInfo heap( void ) { return { heap_allocator_proc, nullptr }; }
|
||||
constexpr AllocatorInfo heap( void ) { AllocatorInfo allocator = { heap_allocator_proc, nullptr }; return allocator; }
|
||||
|
||||
//! Helper to allocate memory using heap allocator.
|
||||
#define malloc( sz ) alloc( heap(), sz )
|
||||
@@ -165,34 +162,97 @@ b32 vm_free( VirtualMemory vm );
|
||||
VirtualMemory vm_trim( VirtualMemory vm, ssize lead_size, ssize size );
|
||||
|
||||
//! Purge virtual memory.
|
||||
b32 gen_vm_purge( VirtualMemory vm );
|
||||
b32 vm_purge( VirtualMemory vm );
|
||||
|
||||
//! Retrieve VM's page size and alignment.
|
||||
ssize gen_virtual_memory_page_size( ssize* alignment_out );
|
||||
ssize virtual_memory_page_size( ssize* alignment_out );
|
||||
|
||||
#pragma region Arena
|
||||
struct Arena;
|
||||
|
||||
AllocatorInfo arena_allocator_info( Arena* arena );
|
||||
|
||||
// Remove static keyword and rename allocator_proc
|
||||
void* arena_allocator_proc(void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags);
|
||||
|
||||
// Add these declarations after the Arena struct
|
||||
Arena arena_init_from_allocator(AllocatorInfo backing, ssize size);
|
||||
Arena arena_init_from_memory ( void* start, ssize size );
|
||||
|
||||
Arena arena_init_sub (Arena* parent, ssize size);
|
||||
ssize arena_alignment_of (Arena* arena, ssize alignment);
|
||||
void arena_check (Arena* arena);
|
||||
void arena_free (Arena* arena);
|
||||
ssize arena_size_remaining(Arena* arena, ssize alignment);
|
||||
|
||||
struct Arena
|
||||
{
|
||||
static
|
||||
void* allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags );
|
||||
AllocatorInfo Backing;
|
||||
void* PhysicalStart;
|
||||
ssize TotalSize;
|
||||
ssize TotalUsed;
|
||||
ssize TempCount;
|
||||
|
||||
static
|
||||
Arena init_from_memory( void* start, ssize size )
|
||||
{
|
||||
return
|
||||
#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP
|
||||
#pragma region Member Mapping
|
||||
forceinline operator AllocatorInfo() { return arena_allocator_info(this); }
|
||||
|
||||
forceinline static void* allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags ) { return arena_allocator_proc( allocator_data, type, size, alignment, old_memory, old_size, flags ); }
|
||||
forceinline static Arena init_from_memory( void* start, ssize size ) { return arena_init_from_memory( start, size ); }
|
||||
forceinline static Arena init_from_allocator( AllocatorInfo backing, ssize size ) { return arena_init_from_allocator( backing, size ); }
|
||||
forceinline static Arena init_sub( Arena& parent, ssize size ) { return arena_init_from_allocator( parent.Backing, size ); }
|
||||
forceinline ssize alignment_of( ssize alignment ) { return arena_alignment_of(this, alignment); }
|
||||
forceinline void free() { return arena_free(this); }
|
||||
forceinline ssize size_remaining( ssize alignment ) { return arena_size_remaining(this, alignment); }
|
||||
|
||||
// This id is defined by Unreal for asserts
|
||||
#pragma push_macro("check")
|
||||
#undef check
|
||||
forceinline void check() { arena_check(this); }
|
||||
#pragma pop_macro("check")
|
||||
|
||||
#pragma endregion Member Mapping
|
||||
#endif
|
||||
};
|
||||
|
||||
#if GEN_COMPILER_CPP
|
||||
forceinline AllocatorInfo allocator_info(Arena& arena ) { return arena_allocator_info(& arena); }
|
||||
forceinline Arena init_sub (Arena& parent, ssize size) { return arena_init_sub( & parent, size); }
|
||||
forceinline ssize alignment_of (Arena& arena, ssize alignment) { return arena_alignment_of( & arena, alignment); }
|
||||
forceinline void free (Arena& arena) { return arena_free(& arena); }
|
||||
forceinline ssize size_remaining(Arena& arena, ssize alignment) { return arena_size_remaining(& arena, alignment); }
|
||||
|
||||
// This id is defined by Unreal for asserts
|
||||
#pragma push_macro("check")
|
||||
#undef check
|
||||
forceinline void check(Arena& arena) { return arena_check(& arena); };
|
||||
#pragma pop_macro("check")
|
||||
#endif
|
||||
|
||||
|
||||
inline
|
||||
AllocatorInfo arena_allocator_info( Arena* arena ) {
|
||||
GEN_ASSERT(arena != nullptr);
|
||||
AllocatorInfo info = { arena_allocator_proc, arena };
|
||||
return info;
|
||||
}
|
||||
|
||||
inline
|
||||
Arena arena_init_from_memory( void* start, ssize size )
|
||||
{
|
||||
Arena arena = {
|
||||
{ nullptr, nullptr },
|
||||
start,
|
||||
size,
|
||||
0,
|
||||
0
|
||||
};
|
||||
return arena;
|
||||
}
|
||||
|
||||
static
|
||||
Arena init_from_allocator( AllocatorInfo backing, ssize size )
|
||||
{
|
||||
Arena result =
|
||||
{
|
||||
inline
|
||||
Arena arena_init_from_allocator(AllocatorInfo backing, ssize size) {
|
||||
Arena result = {
|
||||
backing,
|
||||
alloc(backing, size),
|
||||
size,
|
||||
@@ -202,19 +262,21 @@ struct Arena
|
||||
return result;
|
||||
}
|
||||
|
||||
static
|
||||
Arena init_sub( Arena& parent, ssize size )
|
||||
{
|
||||
return init_from_allocator( parent.Backing, size );
|
||||
inline
|
||||
Arena arena_init_sub(Arena* parent, ssize size) {
|
||||
GEN_ASSERT(parent != nullptr);
|
||||
return arena_init_from_allocator(parent->Backing, size);
|
||||
}
|
||||
|
||||
ssize alignment_of( ssize alignment )
|
||||
inline
|
||||
ssize arena_alignment_of(Arena* arena, ssize alignment)
|
||||
{
|
||||
GEN_ASSERT(arena != nullptr);
|
||||
ssize alignment_offset, result_pointer, mask;
|
||||
GEN_ASSERT(is_power_of_two(alignment));
|
||||
|
||||
alignment_offset = 0;
|
||||
result_pointer = (ssize) PhysicalStart + TotalUsed;
|
||||
result_pointer = (ssize)arena->PhysicalStart + arena->TotalUsed;
|
||||
mask = alignment - 1;
|
||||
|
||||
if (result_pointer & mask)
|
||||
@@ -223,105 +285,119 @@ struct Arena
|
||||
return alignment_offset;
|
||||
}
|
||||
|
||||
// This id is defined by Unreal for asserts
|
||||
#pragma push_macro("check")
|
||||
#undef check
|
||||
void check()
|
||||
inline
|
||||
void arena_check(Arena* arena)
|
||||
{
|
||||
GEN_ASSERT( TempCount == 0 );
|
||||
GEN_ASSERT(arena != nullptr );
|
||||
GEN_ASSERT(arena->TempCount == 0);
|
||||
}
|
||||
#pragma pop_macro("check")
|
||||
|
||||
void free()
|
||||
inline
|
||||
void arena_free(Arena* arena)
|
||||
{
|
||||
if ( Backing.Proc )
|
||||
GEN_ASSERT(arena != nullptr);
|
||||
if (arena->Backing.Proc)
|
||||
{
|
||||
gen::free( Backing, PhysicalStart );
|
||||
PhysicalStart = nullptr;
|
||||
allocator_free(arena->Backing, arena->PhysicalStart);
|
||||
arena->PhysicalStart = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
ssize size_remaining( ssize alignment )
|
||||
inline
|
||||
ssize arena_size_remaining(Arena* arena, ssize alignment)
|
||||
{
|
||||
ssize result = TotalSize - ( TotalUsed + alignment_of( alignment ) );
|
||||
GEN_ASSERT(arena != nullptr);
|
||||
ssize result = arena->TotalSize - (arena->TotalUsed + arena_alignment_of(arena, alignment));
|
||||
return result;
|
||||
}
|
||||
#pragma endregion Arena
|
||||
|
||||
AllocatorInfo Backing;
|
||||
void* PhysicalStart;
|
||||
ssize TotalSize;
|
||||
ssize TotalUsed;
|
||||
ssize TempCount;
|
||||
#pragma region FixedArena
|
||||
template<s32 Size>
|
||||
struct FixedArena;
|
||||
|
||||
operator AllocatorInfo()
|
||||
{
|
||||
return { allocator_proc, this };
|
||||
}
|
||||
};
|
||||
template<s32 Size> FixedArena<Size> fixed_arena_init();
|
||||
template<s32 Size> AllocatorInfo fixed_arena_allocator_info(FixedArena<Size>* fixed_arena );
|
||||
template<s32 Size> ssize fixed_arena_size_remaining(FixedArena<Size>* fixed_arena, ssize alignment);
|
||||
|
||||
#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP
|
||||
template<s32 Size> AllocatorInfo allocator_info( FixedArena<Size>& fixed_arena ) { return allocator_info(& fixed_arena); }
|
||||
template<s32 Size> ssize size_remaining(FixedArena<Size>& fixed_arena, ssize alignment) { return size_remaining( & fixed_arena, alignment); }
|
||||
#endif
|
||||
|
||||
// Just a wrapper around using an arena with memory associated with its scope instead of from an allocator.
|
||||
// Used for static segment or stack allocations.
|
||||
template< s32 Size >
|
||||
struct FixedArena
|
||||
{
|
||||
static
|
||||
FixedArena init()
|
||||
{
|
||||
FixedArena result = { Arena::init_from_memory( result.memory, Size ), {0} };
|
||||
return result;
|
||||
}
|
||||
|
||||
ssize size_remaining( ssize alignment )
|
||||
{
|
||||
return arena.size_remaining( alignment );
|
||||
}
|
||||
|
||||
operator AllocatorInfo()
|
||||
{
|
||||
return { Arena::allocator_proc, &arena };
|
||||
}
|
||||
|
||||
Arena arena;
|
||||
char memory[Size];
|
||||
Arena arena;
|
||||
|
||||
#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP
|
||||
#pragma region Member Mapping
|
||||
forceinline operator AllocatorInfo() { return fixed_arena_allocator_info(this); }
|
||||
|
||||
forceinline static FixedArena init() { FixedArena result; fixed_arena_init<Size>(result); return result; }
|
||||
forceinline ssize size_remaining(ssize alignment) { fixed_arena_size_remaining(this, alignment); }
|
||||
#pragma endregion Member Mapping
|
||||
#endif
|
||||
};
|
||||
|
||||
using Arena_1KB = FixedArena< kilobytes( 1 ) >;
|
||||
using Arena_4KB = FixedArena< kilobytes( 4 ) >;
|
||||
using Arena_8KB = FixedArena< kilobytes( 8 ) >;
|
||||
using Arena_16KB = FixedArena< kilobytes( 16 ) >;
|
||||
using Arena_32KB = FixedArena< kilobytes( 32 ) >;
|
||||
using Arena_64KB = FixedArena< kilobytes( 64 ) >;
|
||||
using Arena_128KB = FixedArena< kilobytes( 128 ) >;
|
||||
using Arena_256KB = FixedArena< kilobytes( 256 ) >;
|
||||
using Arena_512KB = FixedArena< kilobytes( 512 ) >;
|
||||
using Arena_1MB = FixedArena< megabytes( 1 ) >;
|
||||
using Arena_2MB = FixedArena< megabytes( 2 ) >;
|
||||
using Arena_4MB = FixedArena< megabytes( 4 ) >;
|
||||
template<s32 Size> inline
|
||||
AllocatorInfo fixed_arena_allocator_info( FixedArena<Size>* fixed_arena ) {
|
||||
GEN_ASSERT(fixed_arena);
|
||||
return { arena_allocator_proc, & fixed_arena->arena };
|
||||
}
|
||||
|
||||
template<s32 Size> inline
|
||||
void fixed_arena_init(FixedArena<Size>* result) {
|
||||
zero_size(& result->memory[0], Size);
|
||||
result->arena = arena_init_from_memory(& result->memory[0], Size);
|
||||
}
|
||||
|
||||
template<s32 Size> inline
|
||||
void fixed_arena_free(FixedArena<Size>* fixed_arena) {
|
||||
arena_free( & fixed_arena->arena);
|
||||
}
|
||||
|
||||
template<s32 Size> inline
|
||||
ssize fixed_arena_size_remaining(FixedArena<Size>* fixed_arena, ssize alignment) {
|
||||
return size_remaining(fixed_arena->arena, alignment);
|
||||
}
|
||||
|
||||
using FixedArena_1KB = FixedArena< kilobytes( 1 ) >;
|
||||
using FixedArena_4KB = FixedArena< kilobytes( 4 ) >;
|
||||
using FixedArena_8KB = FixedArena< kilobytes( 8 ) >;
|
||||
using FixedArena_16KB = FixedArena< kilobytes( 16 ) >;
|
||||
using FixedArena_32KB = FixedArena< kilobytes( 32 ) >;
|
||||
using FixedArena_64KB = FixedArena< kilobytes( 64 ) >;
|
||||
using FixedArena_128KB = FixedArena< kilobytes( 128 ) >;
|
||||
using FixedArena_256KB = FixedArena< kilobytes( 256 ) >;
|
||||
using FixedArena_512KB = FixedArena< kilobytes( 512 ) >;
|
||||
using FixedArena_1MB = FixedArena< megabytes( 1 ) >;
|
||||
using FixedArena_2MB = FixedArena< megabytes( 2 ) >;
|
||||
using FixedArena_4MB = FixedArena< megabytes( 4 ) >;
|
||||
#pragma endregion FixedArena
|
||||
|
||||
#pragma region Pool
|
||||
struct Pool;
|
||||
|
||||
void* pool_allocator_proc(void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags);
|
||||
|
||||
Pool pool_init(AllocatorInfo backing, ssize num_blocks, ssize block_size);
|
||||
Pool pool_init_align(AllocatorInfo backing, ssize num_blocks, ssize block_size, ssize block_align);
|
||||
AllocatorInfo pool_allocator_info(Pool* pool);
|
||||
void pool_clear(Pool* pool);
|
||||
void pool_free(Pool* pool);
|
||||
|
||||
#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP
|
||||
AllocatorInfo allocator_info(Pool& pool) { return pool_allocator_info(& pool); }
|
||||
void clear(Pool& pool) { return pool_clear(& pool); }
|
||||
void free(Pool& pool) { return pool_free(& pool); }
|
||||
#endif
|
||||
|
||||
struct Pool
|
||||
{
|
||||
static
|
||||
void* allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags );
|
||||
|
||||
static
|
||||
Pool init( AllocatorInfo backing, ssize num_blocks, ssize block_size )
|
||||
{
|
||||
return init_align( backing, num_blocks, block_size, GEN_DEFAULT_MEMORY_ALIGNMENT );
|
||||
}
|
||||
|
||||
static
|
||||
Pool init_align( AllocatorInfo backing, ssize num_blocks, ssize block_size, ssize block_align );
|
||||
|
||||
void clear();
|
||||
|
||||
void free()
|
||||
{
|
||||
if ( Backing.Proc )
|
||||
{
|
||||
gen::free( Backing, PhysicalStart );
|
||||
}
|
||||
}
|
||||
|
||||
AllocatorInfo Backing;
|
||||
void* PhysicalStart;
|
||||
void* FreeList;
|
||||
@@ -330,12 +406,37 @@ struct Pool
|
||||
ssize TotalSize;
|
||||
ssize NumBlocks;
|
||||
|
||||
operator AllocatorInfo()
|
||||
{
|
||||
return { allocator_proc, this };
|
||||
}
|
||||
#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP
|
||||
#pragma region Member Mapping
|
||||
forceinline operator AllocatorInfo() { return pool_allocator_info(this); }
|
||||
|
||||
forceinline static void* allocator_proc(void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags) { return pool_allocator_proc(allocator_data, type, size, alignment, old_memory, old_size, flags); }
|
||||
forceinline static Pool init(AllocatorInfo backing, ssize num_blocks, ssize block_size) { return pool_init(backing, num_blocks, block_size); }
|
||||
forceinline static Pool init_align(AllocatorInfo backing, ssize num_blocks, ssize block_size, ssize block_align) { return pool_init_align(backing, num_blocks, block_size, block_align); }
|
||||
forceinline void clear() { pool_clear( this); }
|
||||
forceinline void free() { pool_free( this); }
|
||||
#pragma endregion
|
||||
#endif
|
||||
};
|
||||
|
||||
inline
|
||||
AllocatorInfo pool_allocator_info(Pool* pool) {
|
||||
AllocatorInfo info = { pool_allocator_proc, pool };
|
||||
return info;
|
||||
}
|
||||
|
||||
inline
|
||||
Pool pool_init(AllocatorInfo backing, ssize num_blocks, ssize block_size) {
|
||||
return pool_init_align(backing, num_blocks, block_size, GEN_DEFAULT_MEMORY_ALIGNMENT);
|
||||
}
|
||||
|
||||
inline
|
||||
void pool_free(Pool* pool) {
|
||||
if(pool->Backing.Proc) {
|
||||
allocator_free(pool->Backing, pool->PhysicalStart);
|
||||
}
|
||||
}
|
||||
#pragma endregion Pool
|
||||
|
||||
inline
|
||||
b32 is_power_of_two( ssize x ) {
|
||||
@@ -354,7 +455,7 @@ mem_ptr align_forward( void* ptr, ssize alignment )
|
||||
return to_mem_ptr(forward);
|
||||
}
|
||||
|
||||
inline s64 align_forward_i64( s64 value, ssize alignment ) { return value + ( alignment - value % alignment ) % alignment; }
|
||||
inline s64 align_forward_s64( s64 value, ssize alignment ) { return value + ( alignment - value % alignment ) % alignment; }
|
||||
|
||||
inline void* pointer_add ( void* ptr, ssize bytes ) { return rcast(void*, rcast( u8*, ptr) + bytes ); }
|
||||
inline void const* pointer_add_const( void const* ptr, ssize bytes ) { return rcast(void const*, rcast( u8 const*, ptr) + bytes ); }
|
||||
@@ -512,7 +613,7 @@ void* alloc( AllocatorInfo a, ssize size ) {
|
||||
}
|
||||
|
||||
inline
|
||||
void free( AllocatorInfo a, void* ptr ) {
|
||||
void allocator_free( AllocatorInfo a, void* ptr ) {
|
||||
if ( ptr != nullptr )
|
||||
a.Proc( a.Data, EAllocation_FREE, 0, 0, ptr, 0, GEN_DEFAULT_ALLOCATOR_FLAGS );
|
||||
}
|
||||
@@ -540,7 +641,7 @@ void* default_resize_align( AllocatorInfo a, void* old_memory, ssize old_size, s
|
||||
|
||||
if ( new_size == 0 )
|
||||
{
|
||||
free( a, old_memory );
|
||||
allocator_free( a, old_memory );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -558,7 +659,7 @@ void* default_resize_align( AllocatorInfo a, void* old_memory, ssize old_size, s
|
||||
return nullptr;
|
||||
|
||||
mem_move( new_memory, old_memory, min( new_size, old_size ) );
|
||||
free( a, old_memory );
|
||||
allocator_free( a, old_memory );
|
||||
return new_memory;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
# pragma once
|
||||
# include "parsing.hpp"
|
||||
#endif
|
||||
|
||||
#pragma region ADT
|
||||
@@ -23,7 +24,7 @@ u8 adt_make_branch( ADT_Node* node, AllocatorInfo backing, char const* name, b32
|
||||
node->type = type;
|
||||
node->name = name;
|
||||
node->parent = parent;
|
||||
node->nodes = Array<ADT_Node>::init( backing );
|
||||
node->nodes = array_init(ADT_Node, backing );
|
||||
|
||||
if ( ! node->nodes )
|
||||
return EADT_ERROR_OUT_OF_MEMORY;
|
||||
@@ -36,12 +37,12 @@ u8 adt_destroy_branch( ADT_Node* node )
|
||||
GEN_ASSERT_NOT_NULL( node );
|
||||
if ( ( node->type == EADT_TYPE_OBJECT || node->type == EADT_TYPE_ARRAY ) && node->nodes )
|
||||
{
|
||||
for ( ssize i = 0; i < scast(ssize, node->nodes.num()); ++i )
|
||||
for ( ssize i = 0; i < scast(ssize, array_num(node->nodes)); ++i )
|
||||
{
|
||||
adt_destroy_branch( node->nodes + i );
|
||||
}
|
||||
|
||||
node->nodes.free();
|
||||
array_free(node->nodes);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -66,7 +67,7 @@ ADT_Node* adt_find( ADT_Node* node, char const* name, b32 deep_search )
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for ( ssize i = 0; i < scast(ssize, node->nodes.num()); i++ )
|
||||
for ( ssize i = 0; i < scast(ssize, array_num(node->nodes)); i++ )
|
||||
{
|
||||
if ( ! str_compare( node->nodes[ i ].name, name ) )
|
||||
{
|
||||
@@ -76,7 +77,7 @@ ADT_Node* adt_find( ADT_Node* node, char const* name, b32 deep_search )
|
||||
|
||||
if ( deep_search )
|
||||
{
|
||||
for ( ssize i = 0; i < scast(ssize, node->nodes.num()); i++ )
|
||||
for ( ssize i = 0; i < scast(ssize, array_num(node->nodes)); i++ )
|
||||
{
|
||||
ADT_Node* res = adt_find( node->nodes + i, name, deep_search );
|
||||
|
||||
@@ -132,7 +133,7 @@ internal ADT_Node* _adt_get_value( ADT_Node* node, char const* value )
|
||||
|
||||
internal ADT_Node* _adt_get_field( ADT_Node* node, char* name, char* value )
|
||||
{
|
||||
for ( ssize i = 0; i < scast(ssize, node->nodes.num()); i++ )
|
||||
for ( ssize i = 0; i < scast(ssize, array_num(node->nodes)); i++ )
|
||||
{
|
||||
if ( ! str_compare( node->nodes[ i ].name, name ) )
|
||||
{
|
||||
@@ -207,7 +208,7 @@ ADT_Node* adt_query( ADT_Node* node, char const* uri )
|
||||
/* run a value comparison against any child that is an object node */
|
||||
else if ( node->type == EADT_TYPE_ARRAY )
|
||||
{
|
||||
for ( ssize i = 0; i < scast(ssize, node->nodes.num()); i++ )
|
||||
for ( ssize i = 0; i < scast(ssize, array_num(node->nodes)); i++ )
|
||||
{
|
||||
ADT_Node* child = &node->nodes[ i ];
|
||||
if ( child->type != EADT_TYPE_OBJECT )
|
||||
@@ -225,7 +226,7 @@ ADT_Node* adt_query( ADT_Node* node, char const* uri )
|
||||
/* [value] */
|
||||
else
|
||||
{
|
||||
for ( ssize i = 0; i < scast(ssize, node->nodes.num()); i++ )
|
||||
for ( ssize i = 0; i < scast(ssize, array_num(node->nodes)); i++ )
|
||||
{
|
||||
ADT_Node* child = &node->nodes[ i ];
|
||||
if ( _adt_get_value( child, l_b2 ) )
|
||||
@@ -257,7 +258,7 @@ ADT_Node* adt_query( ADT_Node* node, char const* uri )
|
||||
else
|
||||
{
|
||||
ssize idx = ( ssize )str_to_i64( buf, NULL, 10 );
|
||||
if ( idx >= 0 && idx < scast(ssize, node->nodes.num()) )
|
||||
if ( idx >= 0 && idx < scast(ssize, array_num(node->nodes)) )
|
||||
{
|
||||
found_node = &node->nodes[ idx ];
|
||||
|
||||
@@ -282,15 +283,16 @@ ADT_Node* adt_alloc_at( ADT_Node* parent, ssize index )
|
||||
if ( ! parent->nodes )
|
||||
return NULL;
|
||||
|
||||
if ( index < 0 || index > scast(ssize, parent->nodes.num()) )
|
||||
if ( index < 0 || index > scast(ssize, array_num(parent->nodes)) )
|
||||
return NULL;
|
||||
|
||||
ADT_Node o = { 0 };
|
||||
o.parent = parent;
|
||||
if ( ! parent->nodes.append_at( o, index ) )
|
||||
if ( ! array_append_at( parent->nodes, o, index ) )
|
||||
return NULL;
|
||||
|
||||
return parent->nodes + index;
|
||||
ADT_Node* node = & parent->nodes[index];
|
||||
return node;
|
||||
}
|
||||
|
||||
ADT_Node* adt_alloc( ADT_Node* parent )
|
||||
@@ -303,7 +305,7 @@ ADT_Node* adt_alloc( ADT_Node* parent )
|
||||
if ( ! parent->nodes )
|
||||
return NULL;
|
||||
|
||||
return adt_alloc_at( parent, parent->nodes.num() );
|
||||
return adt_alloc_at( parent, array_num(parent->nodes) );
|
||||
}
|
||||
|
||||
b8 adt_set_obj( ADT_Node* obj, char const* name, AllocatorInfo backing )
|
||||
@@ -357,7 +359,7 @@ ADT_Node* adt_move_node( ADT_Node* node, ADT_Node* new_parent )
|
||||
GEN_ASSERT_NOT_NULL( node );
|
||||
GEN_ASSERT_NOT_NULL( new_parent );
|
||||
GEN_ASSERT( new_parent->type == EADT_TYPE_ARRAY || new_parent->type == EADT_TYPE_OBJECT );
|
||||
return adt_move_node_at( node, new_parent, new_parent->nodes.num() );
|
||||
return adt_move_node_at( node, new_parent, array_num(new_parent->nodes) );
|
||||
}
|
||||
|
||||
void adt_swap_nodes( ADT_Node* node, ADT_Node* other_node )
|
||||
@@ -381,7 +383,7 @@ void adt_remove_node( ADT_Node* node )
|
||||
GEN_ASSERT_NOT_NULL( node->parent );
|
||||
ADT_Node* parent = node->parent;
|
||||
ssize index = ( pointer_diff( parent->nodes, node ) / size_of( ADT_Node ) );
|
||||
parent->nodes.remove_at( index );
|
||||
array_remove_at( parent->nodes, index );
|
||||
}
|
||||
|
||||
ADT_Node* adt_append_obj( ADT_Node* parent, char const* name )
|
||||
@@ -389,7 +391,7 @@ ADT_Node* adt_append_obj( ADT_Node* parent, char const* name )
|
||||
ADT_Node* o = adt_alloc( parent );
|
||||
if ( ! o )
|
||||
return NULL;
|
||||
if ( adt_set_obj( o, name, parent->nodes.get_header()->Allocator ) )
|
||||
if ( adt_set_obj( o, name, array_get_header(parent->nodes)->Allocator ) )
|
||||
{
|
||||
adt_remove_node( o );
|
||||
return NULL;
|
||||
@@ -402,7 +404,9 @@ ADT_Node* adt_append_arr( ADT_Node* parent, char const* name )
|
||||
ADT_Node* o = adt_alloc( parent );
|
||||
if ( ! o )
|
||||
return NULL;
|
||||
if ( adt_set_arr( o, name, parent->nodes.get_header()->Allocator ) )
|
||||
|
||||
ArrayHeader* node_header = array_get_header(parent->nodes);
|
||||
if ( adt_set_arr( o, name, node_header->Allocator ) )
|
||||
{
|
||||
adt_remove_node( o );
|
||||
return NULL;
|
||||
@@ -447,7 +451,7 @@ char* adt_parse_number_strict( ADT_Node* node, char* base_str )
|
||||
while ( *e )
|
||||
++e;
|
||||
|
||||
while ( *p && ( str_find( "eE.+-", *p ) || char_is_hex_digit( *p ) ) )
|
||||
while ( *p && ( char_first_occurence( "eE.+-", *p ) || char_is_hex_digit( *p ) ) )
|
||||
{
|
||||
++p;
|
||||
}
|
||||
@@ -476,7 +480,7 @@ char* adt_parse_number( ADT_Node* node, char* base_str )
|
||||
u8 node_props = 0;
|
||||
|
||||
/* skip false positives and special cases */
|
||||
if ( ! ! str_find( "eE", *p ) || ( ! ! str_find( ".+-", *p ) && ! char_is_hex_digit( *( p + 1 ) ) && *( p + 1 ) != '.' ) )
|
||||
if ( ! ! char_first_occurence( "eE", *p ) || ( ! ! char_first_occurence( ".+-", *p ) && ! char_is_hex_digit( *( p + 1 ) ) && *( p + 1 ) != '.' ) )
|
||||
{
|
||||
return ++base_str;
|
||||
}
|
||||
@@ -507,7 +511,7 @@ char* adt_parse_number( ADT_Node* node, char* base_str )
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( ! str_compare( e, "0x", 2 ) || ! str_compare( e, "0X", 2 ) )
|
||||
if ( ! str_compare_len( e, "0x", 2 ) || ! str_compare_len( e, "0X", 2 ) )
|
||||
{
|
||||
node_props = EADT_PROPS_IS_HEX;
|
||||
}
|
||||
@@ -552,7 +556,7 @@ char* adt_parse_number( ADT_Node* node, char* base_str )
|
||||
char expbuf[ 6 ] = { 0 };
|
||||
ssize expi = 0;
|
||||
|
||||
if ( *e && ! ! str_find( "eE", *e ) )
|
||||
if ( *e && ! ! char_first_occurence( "eE", *e ) )
|
||||
{
|
||||
++e;
|
||||
if ( *e == '+' || *e == '-' || char_is_digit( *e ) )
|
||||
@@ -748,7 +752,7 @@ ADT_Error adt_print_string( FileInfo* file, ADT_Node* node, char const* escaped_
|
||||
{
|
||||
p = str_skip_any( p, escaped_chars );
|
||||
_adt_fprintf( file, "%.*s", pointer_diff( b, p ), b );
|
||||
if ( *p && ! ! str_find( escaped_chars, *p ) )
|
||||
if ( *p && ! ! char_first_occurence( escaped_chars, *p ) )
|
||||
{
|
||||
_adt_fprintf( file, "%s%c", escape_symbol, *p );
|
||||
p++;
|
||||
@@ -946,12 +950,12 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b
|
||||
}
|
||||
}
|
||||
|
||||
if ( columnIndex >= scast(ssize, root->nodes.num()) )
|
||||
if ( columnIndex >= scast(ssize, array_num(root->nodes)) )
|
||||
{
|
||||
adt_append_arr( root, NULL );
|
||||
}
|
||||
|
||||
root->nodes[ columnIndex ].nodes.append( rowItem );
|
||||
array_append( root->nodes[ columnIndex ].nodes, rowItem );
|
||||
|
||||
if ( delimiter == delim )
|
||||
{
|
||||
@@ -979,7 +983,7 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b
|
||||
}
|
||||
while ( *currentChar );
|
||||
|
||||
if ( root->nodes.num() == 0 )
|
||||
if (array_num( root->nodes) == 0 )
|
||||
{
|
||||
GEN_CSV_ASSERT( "unexpected end of input. stream is empty." );
|
||||
error = ECSV_Error__UNEXPECTED_END_OF_INPUT;
|
||||
@@ -989,12 +993,12 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b
|
||||
/* consider first row as a header. */
|
||||
if ( has_header )
|
||||
{
|
||||
for ( ssize i = 0; i < scast(ssize, root->nodes.num()); i++ )
|
||||
for ( ssize i = 0; i < scast(ssize, array_num(root->nodes)); i++ )
|
||||
{
|
||||
CSV_Object* col = root->nodes + i;
|
||||
CSV_Object* hdr = col->nodes;
|
||||
col->name = hdr->string;
|
||||
col->nodes.remove_at( 0 );
|
||||
array_remove_at(col->nodes, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1057,11 +1061,11 @@ void csv_write_delimiter( FileInfo* file, CSV_Object* obj, char delimiter )
|
||||
GEN_ASSERT_NOT_NULL( file );
|
||||
GEN_ASSERT_NOT_NULL( obj );
|
||||
GEN_ASSERT( obj->nodes );
|
||||
ssize cols = obj->nodes.num();
|
||||
ssize cols = array_num(obj->nodes);
|
||||
if ( cols == 0 )
|
||||
return;
|
||||
|
||||
ssize rows = obj->nodes[ 0 ].nodes.num();
|
||||
ssize rows = array_num(obj->nodes[ 0 ].nodes);
|
||||
if ( rows == 0 )
|
||||
return;
|
||||
|
||||
@@ -1102,10 +1106,9 @@ String csv_write_string_delimiter( AllocatorInfo a, CSV_Object* obj, char delimi
|
||||
|
||||
ssize fsize;
|
||||
u8* buf = file_stream_buf( &tmp, &fsize );
|
||||
String output = String::make_length( a, ( char* )buf, fsize );
|
||||
String output = string_make_length( a, ( char* )buf, fsize );
|
||||
file_close( &tmp );
|
||||
return output;
|
||||
}
|
||||
|
||||
#pragma endregion CSV
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ struct ADT_Node
|
||||
union
|
||||
{
|
||||
char const* string;
|
||||
Array<ADT_Node> nodes; ///< zpl_array
|
||||
Array(ADT_Node) nodes; ///< zpl_array
|
||||
|
||||
struct
|
||||
{
|
||||
|
||||
@@ -76,13 +76,21 @@
|
||||
/* Platform compiler */
|
||||
|
||||
#if defined( _MSC_VER )
|
||||
# pragma message("Detected MSVC")
|
||||
// # define GEN_COMPILER_CLANG 0
|
||||
# define GEN_COMPILER_MSVC 1
|
||||
// # define GEN_COMPILER_GCC 0
|
||||
#elif defined( __GNUC__ )
|
||||
# pragma message("Detected GCC")
|
||||
// # define GEN_COMPILER_CLANG 0
|
||||
// # define GEN_COMPILER_MSVC 0
|
||||
# define GEN_COMPILER_GCC 1
|
||||
#elif defined( __clang__ )
|
||||
# pragma message("Detected CLANG")
|
||||
# define GEN_COMPILER_CLANG 1
|
||||
#elif defined( __MINGW32__ )
|
||||
# define GEN_COMPILER_MINGW 1
|
||||
// # define GEN_COMPILER_MSVC 0
|
||||
// # define GEN_COMPILER_GCC 0
|
||||
#else
|
||||
# error Unknown compiler
|
||||
#endif
|
||||
|
||||
@@ -101,6 +109,26 @@
|
||||
# define GEN_GCC_VERSION_CHECK(major,minor,patch) (0)
|
||||
#endif
|
||||
|
||||
#if !defined(GEN_COMPILER_C)
|
||||
# ifdef __cplusplus
|
||||
# define GEN_COMPILER_C 0
|
||||
# define GEN_COMPILER_CPP 1
|
||||
# else
|
||||
# if defined(__STDC__)
|
||||
# define GEN_COMPILER_C 1
|
||||
# define GEN_COMPILER_CPP 0
|
||||
# else
|
||||
// Fallback for very old C compilers
|
||||
# define GEN_COMPILER_C 1
|
||||
# define GEN_COMPILER_CPP 0
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if GEN_COMPILER_C
|
||||
#pragma message("GENCPP: Detected C")
|
||||
#endif
|
||||
|
||||
#pragma endregion Platform Detection
|
||||
|
||||
#pragma region Mandatory Includes
|
||||
@@ -112,13 +140,36 @@
|
||||
# include <intrin.h>
|
||||
# endif
|
||||
|
||||
#if GEN_COMPILER_C
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
#pragma endregion Mandatory Includes
|
||||
|
||||
#ifdef GEN_DONT_USE_NAMESPACE
|
||||
#if GEN_DONT_USE_NAMESPACE || GEN_COMPILER_C
|
||||
# if GEN_COMPILER_C
|
||||
# define GEN_NS_PARSER_BEGIN
|
||||
# define GEN_NS_PARSER_END
|
||||
# define GEN_USING_NS_PARSER
|
||||
# define GEN_NS_PARSER
|
||||
# define GEN_NS
|
||||
# define GEN_NS_BEGIN
|
||||
# define GEN_NS_END
|
||||
# else
|
||||
# define GEN_NS_PARSER_BEGIN namespace parser {
|
||||
# define GEN_NS_PARSER_END }
|
||||
# define GEN_USING_NS_PARSER using namespace parser
|
||||
# define GEN_NS_PARSER parser::
|
||||
# define GEN_NS ::
|
||||
# define GEN_NS_BEGIN
|
||||
# define GEN_NS_END
|
||||
# endif
|
||||
#else
|
||||
# define GEN_NS_PARSER_BEGIN namespace parser {
|
||||
# define GEN_NS_PARSER_END }
|
||||
# define GEN_NS_PARSER parser::
|
||||
# define GEN_USING_NS_PARSER using namespace parser
|
||||
# define GEN_NS gen::
|
||||
# define GEN_NS_BEGIN namespace gen {
|
||||
# define GEN_NS_END }
|
||||
|
||||
@@ -33,6 +33,7 @@ enum
|
||||
GEN_FMT_INTS = GEN_FMT_CHAR | GEN_FMT_SHORT | GEN_FMT_INT | GEN_FMT_LONG | GEN_FMT_LLONG | GEN_FMT_SIZE | GEN_FMT_INTPTR
|
||||
};
|
||||
|
||||
typedef struct _format_info _format_info;
|
||||
struct _format_info
|
||||
{
|
||||
s32 base;
|
||||
@@ -420,9 +421,18 @@ neverinline ssize str_fmt_va( char* text, ssize max_len, char const* fmt, va_lis
|
||||
|
||||
case 'S':
|
||||
{
|
||||
String gen_str = String { va_arg( va, char*) };
|
||||
if ( *(fmt + 1) == 'C' )
|
||||
{
|
||||
++ fmt;
|
||||
StrC gen_str = va_arg( va, StrC);
|
||||
info.precision = gen_str.Len;
|
||||
len = _print_string( text, remaining, &info, gen_str.Ptr );
|
||||
break;
|
||||
}
|
||||
|
||||
info.precision = gen_str.length();
|
||||
String gen_str = { va_arg( va, char*) };
|
||||
|
||||
info.precision = string_length(gen_str);
|
||||
len = _print_string( text, remaining, &info, gen_str );
|
||||
}
|
||||
break;
|
||||
@@ -540,7 +550,7 @@ char* str_fmt_buf( char const* fmt, ... )
|
||||
return str;
|
||||
}
|
||||
|
||||
ssize str_fmt_file_va( struct FileInfo* f, char const* fmt, va_list va )
|
||||
ssize str_fmt_file_va( FileInfo* f, char const* fmt, va_list va )
|
||||
{
|
||||
local_persist thread_local char buf[ GEN_PRINTF_MAXLEN ];
|
||||
ssize len = str_fmt_va( buf, size_of( buf ), fmt, va );
|
||||
@@ -548,7 +558,7 @@ ssize str_fmt_file_va( struct FileInfo* f, char const* fmt, va_list va )
|
||||
return res ? len : -1;
|
||||
}
|
||||
|
||||
ssize str_fmt_file( struct FileInfo* f, char const* fmt, ... )
|
||||
ssize str_fmt_file( FileInfo* f, char const* fmt, ... )
|
||||
{
|
||||
ssize res;
|
||||
va_list va;
|
||||
|
||||
@@ -5,11 +5,12 @@
|
||||
|
||||
#pragma region Printing
|
||||
|
||||
struct FileInfo;
|
||||
typedef struct FileInfo FileInfo;
|
||||
|
||||
#ifndef GEN_PRINTF_MAXLEN
|
||||
# define GEN_PRINTF_MAXLEN kilobytes(128)
|
||||
#endif
|
||||
typedef char PrintF_Buffer[GEN_PRINTF_MAXLEN];
|
||||
|
||||
// NOTE: A locally persisting buffer is used internally
|
||||
char* str_fmt_buf ( char const* fmt, ... );
|
||||
|
||||
@@ -19,7 +19,7 @@ ssize _scan_zpl_i64( const char* text, s32 base, s64* value )
|
||||
text++;
|
||||
}
|
||||
|
||||
if ( base == 16 && str_compare( text, "0x", 2 ) == 0 )
|
||||
if ( base == 16 && str_compare_len( text, "0x", 2 ) == 0 )
|
||||
text += 2;
|
||||
|
||||
for ( ;; )
|
||||
@@ -61,7 +61,7 @@ s64 str_to_i64( const char* str, char** end_ptr, s32 base )
|
||||
|
||||
if ( ! base )
|
||||
{
|
||||
if ( ( str_len( str ) > 2 ) && ( str_compare( str, "0x", 2 ) == 0 ) )
|
||||
if ( ( str_len( str ) > 2 ) && ( str_compare_len( str, "0x", 2 ) == 0 ) )
|
||||
base = 16;
|
||||
else
|
||||
base = 10;
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#pragma region String Ops
|
||||
|
||||
const char* char_first_occurence( const char* str, char c );
|
||||
constexpr auto str_find = &char_first_occurence;
|
||||
|
||||
b32 char_is_alpha( char c );
|
||||
b32 char_is_alphanumeric( char c );
|
||||
@@ -20,11 +19,11 @@ s32 digit_to_int( char c );
|
||||
s32 hex_digit_to_int( char c );
|
||||
|
||||
s32 str_compare( const char* s1, const char* s2 );
|
||||
s32 str_compare( const char* s1, const char* s2, ssize len );
|
||||
s32 str_compare_len( const char* s1, const char* s2, ssize len );
|
||||
char* str_copy( char* dest, const char* source, ssize len );
|
||||
ssize str_copy_nulpad( char* dest, const char* source, ssize len );
|
||||
ssize str_len( const char* str );
|
||||
ssize str_len( const char* str, ssize max_len );
|
||||
ssize str_len_capped( const char* str, ssize max_len );
|
||||
char* str_reverse( char* str ); // NOTE: ASCII only
|
||||
char const* str_skip( char const* str, char c );
|
||||
char const* str_skip_any( char const* str, char const* char_list );
|
||||
@@ -133,7 +132,7 @@ s32 str_compare( const char* s1, const char* s2 )
|
||||
}
|
||||
|
||||
inline
|
||||
s32 str_compare( const char* s1, const char* s2, ssize len )
|
||||
s32 str_compare_len( const char* s1, const char* s2, ssize len )
|
||||
{
|
||||
for ( ; len > 0; s1++, s2++, len-- )
|
||||
{
|
||||
@@ -205,7 +204,7 @@ ssize str_len( const char* str )
|
||||
}
|
||||
|
||||
inline
|
||||
ssize str_len( const char* str, ssize max_len )
|
||||
ssize str_len_capped( const char* str, ssize max_len )
|
||||
{
|
||||
const char* end = rcast(const char*, mem_find( str, 0, max_len ));
|
||||
if ( end )
|
||||
@@ -241,7 +240,7 @@ char const* str_skip( char const* str, char c )
|
||||
inline
|
||||
char const* str_skip_any( char const* str, char const* char_list )
|
||||
{
|
||||
char const* closest_ptr = rcast( char const*, pointer_add_const( rcast(void const*, str), str_len( str ) ));
|
||||
char const* closest_ptr = rcast( char const*, pointer_add_const( rcast(mem_ptr_const, str), str_len( str ) ));
|
||||
ssize char_list_count = str_len( char_list );
|
||||
for ( ssize i = 0; i < char_list_count; i++ )
|
||||
{
|
||||
|
||||
@@ -5,29 +5,23 @@
|
||||
|
||||
#pragma region String
|
||||
|
||||
String String::fmt( AllocatorInfo allocator, char* buf, ssize buf_size, char const* fmt, ... )
|
||||
String string_make_length( AllocatorInfo allocator, char const* str, ssize length )
|
||||
{
|
||||
va_list va;
|
||||
va_start( va, fmt );
|
||||
str_fmt_va( buf, buf_size, fmt, va );
|
||||
va_end( va );
|
||||
|
||||
return make( allocator, buf );
|
||||
}
|
||||
|
||||
String String::make_length( AllocatorInfo allocator, char const* str, ssize length )
|
||||
{
|
||||
constexpr ssize header_size = sizeof( Header );
|
||||
ssize const header_size = sizeof( StringHeader );
|
||||
|
||||
s32 alloc_size = header_size + length + 1;
|
||||
void* allocation = alloc( allocator, alloc_size );
|
||||
|
||||
if ( allocation == nullptr )
|
||||
return { nullptr };
|
||||
if ( allocation == nullptr ) {
|
||||
String null_string = {nullptr};
|
||||
return null_string;
|
||||
}
|
||||
|
||||
Header&
|
||||
header = * rcast(Header*, allocation);
|
||||
header = { allocator, length, length };
|
||||
StringHeader*
|
||||
header = rcast(StringHeader*, allocation);
|
||||
header->Allocator = allocator;
|
||||
header->Capacity = length;
|
||||
header->Length = length;
|
||||
|
||||
String result = { rcast( char*, allocation) + header_size };
|
||||
|
||||
@@ -41,20 +35,21 @@ String String::make_length( AllocatorInfo allocator, char const* str, ssize leng
|
||||
return result;
|
||||
}
|
||||
|
||||
String String::make_reserve( AllocatorInfo allocator, ssize capacity )
|
||||
String string_make_reserve( AllocatorInfo allocator, ssize capacity )
|
||||
{
|
||||
constexpr ssize header_size = sizeof( Header );
|
||||
ssize const header_size = sizeof( StringHeader );
|
||||
|
||||
s32 alloc_size = header_size + capacity + 1;
|
||||
void* allocation = alloc( allocator, alloc_size );
|
||||
|
||||
if ( allocation == nullptr )
|
||||
return { nullptr };
|
||||
|
||||
if ( allocation == nullptr ) {
|
||||
String null_string = {nullptr};
|
||||
return null_string;
|
||||
}
|
||||
mem_set( allocation, 0, alloc_size );
|
||||
|
||||
Header*
|
||||
header = rcast(Header*, allocation);
|
||||
StringHeader*
|
||||
header = rcast(StringHeader*, allocation);
|
||||
header->Allocator = allocator;
|
||||
header->Capacity = capacity;
|
||||
header->Length = 0;
|
||||
@@ -63,68 +58,4 @@ String String::make_reserve( AllocatorInfo allocator, ssize capacity )
|
||||
return result;
|
||||
}
|
||||
|
||||
String String::fmt_buf( AllocatorInfo allocator, char const* fmt, ... )
|
||||
{
|
||||
local_persist thread_local
|
||||
char buf[ GEN_PRINTF_MAXLEN ] = { 0 };
|
||||
|
||||
va_list va;
|
||||
va_start( va, fmt );
|
||||
str_fmt_va( buf, GEN_PRINTF_MAXLEN, fmt, va );
|
||||
va_end( va );
|
||||
|
||||
return make( allocator, buf );
|
||||
}
|
||||
|
||||
bool String::append_fmt( char const* fmt, ... )
|
||||
{
|
||||
ssize res;
|
||||
char buf[ GEN_PRINTF_MAXLEN ] = { 0 };
|
||||
|
||||
va_list va;
|
||||
va_start( va, fmt );
|
||||
res = str_fmt_va( buf, count_of( buf ) - 1, fmt, va ) - 1;
|
||||
va_end( va );
|
||||
|
||||
return append( buf, res );
|
||||
}
|
||||
|
||||
bool String::make_space_for( char const* str, ssize add_len )
|
||||
{
|
||||
ssize available = avail_space();
|
||||
|
||||
// NOTE: Return if there is enough space left
|
||||
if ( available >= add_len )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ssize new_len, old_size, new_size;
|
||||
|
||||
void* ptr;
|
||||
void* new_ptr;
|
||||
|
||||
AllocatorInfo allocator = get_header().Allocator;
|
||||
Header* header = nullptr;
|
||||
|
||||
new_len = grow_formula( length() + add_len );
|
||||
ptr = & get_header();
|
||||
old_size = size_of( Header ) + length() + 1;
|
||||
new_size = size_of( Header ) + new_len + 1;
|
||||
|
||||
new_ptr = resize( allocator, ptr, old_size, new_size );
|
||||
|
||||
if ( new_ptr == nullptr )
|
||||
return false;
|
||||
|
||||
header = rcast( Header*, new_ptr);
|
||||
header->Allocator = allocator;
|
||||
header->Capacity = new_len;
|
||||
|
||||
Data = rcast( char*, header + 1 );
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#pragma endregion String
|
||||
|
||||
+548
-219
@@ -5,255 +5,604 @@
|
||||
|
||||
#pragma region Strings
|
||||
|
||||
struct StrC;
|
||||
|
||||
StrC to_strc_from_c_str (char const* bad_string);
|
||||
bool strc_are_equal (StrC lhs, StrC rhs);
|
||||
char const* strc_back (StrC str);
|
||||
bool strc_contains (StrC str, StrC substring);
|
||||
StrC strc_duplicate (StrC str, AllocatorInfo allocator);
|
||||
b32 strc_starts_with (StrC str, StrC substring);
|
||||
StrC strc_visualize_whitespace(StrC str, AllocatorInfo allocator);
|
||||
|
||||
// Constant string with length.
|
||||
struct StrC
|
||||
{
|
||||
ssize Len;
|
||||
char const* Ptr;
|
||||
|
||||
operator char const* () const { return Ptr; }
|
||||
char const& operator[]( ssize index ) const { return Ptr[index]; }
|
||||
#if GEN_COMPILER_CPP
|
||||
forceinline operator char const* () const { return Ptr; }
|
||||
forceinline char const& operator[]( ssize index ) const { return Ptr[index]; }
|
||||
|
||||
#if ! GEN_C_LIKE_CPP
|
||||
forceinline bool is_equal (StrC rhs) const { return strc_are_equal(* this, rhs); }
|
||||
forceinline char const* back () const { return strc_back(* this); }
|
||||
forceinline bool contains (StrC substring) const { return strc_contains(* this, substring); }
|
||||
forceinline StrC duplicate (AllocatorInfo allocator) const { return strc_duplicate(* this, allocator); }
|
||||
forceinline b32 starts_with (StrC substring) const { return strc_starts_with(* this, substring); }
|
||||
forceinline StrC visualize_whitespace(AllocatorInfo allocator) const { return strc_visualize_whitespace(* this, allocator); }
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
#define cast_to_strc( str ) * rcast( StrC*, (str) - sizeof(ssize) )
|
||||
|
||||
#ifndef txt
|
||||
# if GEN_COMPILER_CPP
|
||||
# define txt( text ) StrC { sizeof( text ) - 1, ( text ) }
|
||||
# else
|
||||
# define txt( text ) (StrC){ sizeof( text ) - 1, ( text ) }
|
||||
# endif
|
||||
#endif
|
||||
|
||||
GEN_API_C_BEGIN
|
||||
forceinline char const* strc_begin(StrC str) { return str.Ptr; }
|
||||
forceinline char const* strc_end (StrC str) { return str.Ptr + str.Len; }
|
||||
forceinline char const* strc_next (StrC str, char const* iter) { return iter + 1; }
|
||||
GEN_API_C_END
|
||||
|
||||
#if GEN_COMPILER_CPP
|
||||
forceinline char const* begin(StrC str) { return str.Ptr; }
|
||||
forceinline char const* end (StrC str) { return str.Ptr + str.Len; }
|
||||
forceinline char const* next (StrC str, char const* iter) { return iter + 1; }
|
||||
#endif
|
||||
|
||||
inline
|
||||
StrC to_str( char const* str )
|
||||
bool strc_are_equal(StrC lhs, StrC rhs)
|
||||
{
|
||||
return { str_len( str ), str };
|
||||
if (lhs.Len != rhs.Len)
|
||||
return false;
|
||||
|
||||
for (ssize idx = 0; idx < lhs.Len; ++idx)
|
||||
if (lhs.Ptr[idx] != rhs.Ptr[idx])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline
|
||||
char const* strc_back(StrC str) {
|
||||
return & str.Ptr[str.Len - 1];
|
||||
}
|
||||
|
||||
inline
|
||||
bool strc_contains(StrC str, StrC substring)
|
||||
{
|
||||
if (substring.Len > str.Len)
|
||||
return false;
|
||||
|
||||
ssize main_len = str.Len;
|
||||
ssize sub_len = substring.Len;
|
||||
for (ssize idx = 0; idx <= main_len - sub_len; ++idx)
|
||||
{
|
||||
if (str_compare_len(str.Ptr + idx, substring.Ptr, sub_len) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline
|
||||
b32 strc_starts_with(StrC str, StrC substring) {
|
||||
if (substring.Len > str.Len)
|
||||
return false;
|
||||
|
||||
b32 result = str_compare_len(str.Ptr, substring.Ptr, substring.Len) == 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline
|
||||
StrC to_strc_from_c_str( char const* bad_str ) {
|
||||
StrC result = { str_len( bad_str ), bad_str };
|
||||
return result;
|
||||
}
|
||||
|
||||
// Dynamic String
|
||||
// This is directly based off the ZPL string api.
|
||||
// They used a header pattern
|
||||
// I kept it for simplicty of porting but its not necessary to keep it that way.
|
||||
struct String
|
||||
{
|
||||
struct Header
|
||||
{
|
||||
#pragma region String
|
||||
struct StringHeader;
|
||||
|
||||
#if GEN_COMPILER_C
|
||||
typedef char* String;
|
||||
#else
|
||||
struct String;
|
||||
#endif
|
||||
|
||||
forceinline usize string_grow_formula(usize value);
|
||||
|
||||
String string_make_c_str (AllocatorInfo allocator, char const* str);
|
||||
String string_make_strc (AllocatorInfo allocator, StrC str);
|
||||
String string_make_reserve (AllocatorInfo allocator, ssize capacity);
|
||||
String string_make_length (AllocatorInfo allocator, char const* str, ssize length);
|
||||
String string_fmt (AllocatorInfo allocator, char* buf, ssize buf_size, char const* fmt, ...);
|
||||
String string_fmt_buf (AllocatorInfo allocator, char const* fmt, ...);
|
||||
String string_join (AllocatorInfo allocator, char const** parts, ssize num_parts, char const* glue);
|
||||
bool string_are_equal (String const lhs, String const rhs);
|
||||
bool string_are_equal_strc (String const lhs, StrC rhs);
|
||||
bool string_make_space_for (String* str, char const* to_append, ssize add_len);
|
||||
bool string_append_char (String* str, char c);
|
||||
bool string_append_c_str (String* str, char const* str_to_append);
|
||||
bool string_append_c_str_len (String* str, char const* str_to_append, ssize length);
|
||||
bool string_append_strc (String* str, StrC str_to_append);
|
||||
bool string_append_string (String* str, String const other);
|
||||
bool string_append_fmt (String* str, char const* fmt, ...);
|
||||
ssize string_avail_space (String const str);
|
||||
char* string_back (String str);
|
||||
bool string_contains_strc (String const str, StrC substring);
|
||||
bool string_contains_string (String const str, String const substring);
|
||||
ssize string_capacity (String const str);
|
||||
void string_clear (String str);
|
||||
String string_duplicate (String const str, AllocatorInfo allocator);
|
||||
void string_free (String* str);
|
||||
StringHeader* string_get_header (String str);
|
||||
ssize string_length (String const str);
|
||||
b32 string_starts_with_strc (String const str, StrC substring);
|
||||
b32 string_starts_with_string (String const str, String substring);
|
||||
void string_skip_line (String str);
|
||||
void string_strip_space (String str);
|
||||
StrC string_to_strc (String str);
|
||||
void string_trim (String str, char const* cut_set);
|
||||
void string_trim_space (String str);
|
||||
String string_visualize_whitespace(String const str);
|
||||
|
||||
struct StringHeader {
|
||||
AllocatorInfo Allocator;
|
||||
ssize Capacity;
|
||||
ssize Length;
|
||||
};
|
||||
|
||||
static
|
||||
usize grow_formula( usize value )
|
||||
#if GEN_COMPILER_CPP
|
||||
struct String
|
||||
{
|
||||
char* Data;
|
||||
|
||||
forceinline operator char*() { return Data; }
|
||||
forceinline operator char const*() const { return Data; }
|
||||
forceinline operator StrC() const { return { string_length(* this), Data }; }
|
||||
|
||||
String const& operator=(String const& other) const {
|
||||
if (this == &other)
|
||||
return *this;
|
||||
|
||||
String* this_ = ccast(String*, this);
|
||||
this_->Data = other.Data;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
forceinline char& operator[](ssize index) { return Data[index]; }
|
||||
forceinline char const& operator[](ssize index) const { return Data[index]; }
|
||||
|
||||
forceinline bool operator==(std::nullptr_t) const { return Data == nullptr; }
|
||||
forceinline bool operator!=(std::nullptr_t) const { return Data != nullptr; }
|
||||
friend forceinline bool operator==(std::nullptr_t, const String str) { return str.Data == nullptr; }
|
||||
friend forceinline bool operator!=(std::nullptr_t, const String str) { return str.Data != nullptr; }
|
||||
|
||||
#if ! GEN_C_LIKE_CPP
|
||||
forceinline char* begin() const { return Data; }
|
||||
forceinline char* end() const { return Data + string_length(* this); }
|
||||
|
||||
#pragma region Member Mapping
|
||||
forceinline static String make(AllocatorInfo allocator, char const* str) { return string_make_c_str(allocator, str); }
|
||||
forceinline static String make(AllocatorInfo allocator, StrC str) { return string_make_strc(allocator, str); }
|
||||
forceinline static String make_reserve(AllocatorInfo allocator, ssize cap) { return string_make_reserve(allocator, cap); }
|
||||
forceinline static String make_length(AllocatorInfo a, char const* s, ssize l) { return string_make_length(a, s, l); }
|
||||
forceinline static String join(AllocatorInfo a, char const** p, ssize n, char const* g) { return string_join(a, p, n, g); }
|
||||
forceinline static usize grow_formula(usize value) { return string_grow_formula(value); }
|
||||
|
||||
static
|
||||
String fmt(AllocatorInfo allocator, char* buf, ssize buf_size, char const* fmt, ...) {
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
ssize res = str_fmt_va(buf, buf_size, fmt, va) - 1;
|
||||
va_end(va);
|
||||
return string_make_length(allocator, buf, res);
|
||||
}
|
||||
|
||||
static
|
||||
String fmt_buf(AllocatorInfo allocator, char const* fmt, ...) {
|
||||
local_persist thread_local
|
||||
char buf[GEN_PRINTF_MAXLEN] = { 0 };
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
ssize res = str_fmt_va(buf, GEN_PRINTF_MAXLEN, fmt, va) - 1;
|
||||
va_end(va);
|
||||
return string_make_length(allocator, buf, res);
|
||||
}
|
||||
|
||||
forceinline bool make_space_for(char const* str, ssize add_len) { return string_make_space_for(this, str, add_len); }
|
||||
forceinline bool append(char c) { return string_append_char(this, c); }
|
||||
forceinline bool append(char const* str) { return string_append_c_str(this, str); }
|
||||
forceinline bool append(char const* str, ssize length) { return string_append_c_str_len(this, str, length); }
|
||||
forceinline bool append(StrC str) { return string_append_strc(this, str); }
|
||||
forceinline bool append(const String other) { return string_append_string(this, other); }
|
||||
forceinline ssize avail_space() const { return string_avail_space(* this); }
|
||||
forceinline char* back() { return string_back(* this); }
|
||||
forceinline bool contains(StrC substring) const { return string_contains_strc(* this, substring); }
|
||||
forceinline bool contains(String const& substring) const { return string_contains_string(* this, substring); }
|
||||
forceinline ssize capacity() const { return string_capacity(* this); }
|
||||
forceinline void clear() { string_clear(* this); }
|
||||
forceinline String duplicate(AllocatorInfo allocator) const { return string_duplicate(* this, allocator); }
|
||||
forceinline void free() { string_free(this); }
|
||||
forceinline bool is_equal(String const& other) const { return string_are_equal(* this, other); }
|
||||
forceinline bool is_equal(StrC other) const { return string_are_equal_strc(* this, other); }
|
||||
forceinline ssize length() const { return string_length(* this); }
|
||||
forceinline b32 starts_with(StrC substring) const { return string_starts_with_strc(* this, substring); }
|
||||
forceinline b32 starts_with(String substring) const { return string_starts_with_string(* this, substring); }
|
||||
forceinline void skip_line() { string_skip_line(* this); }
|
||||
forceinline void strip_space() { string_strip_space(* this); }
|
||||
forceinline StrC to_strc() { return { string_length(*this), Data}; }
|
||||
forceinline void trim(char const* cut_set) { string_trim(* this, cut_set); }
|
||||
forceinline void trim_space() { string_trim_space(* this); }
|
||||
forceinline String visualize_whitespace() const { return string_visualize_whitespace(* this); }
|
||||
forceinline StringHeader& get_header() { return * string_get_header(* this); }
|
||||
|
||||
bool append_fmt(char const* fmt, ...) {
|
||||
ssize res;
|
||||
char buf[GEN_PRINTF_MAXLEN] = { 0 };
|
||||
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
res = str_fmt_va(buf, count_of(buf) - 1, fmt, va) - 1;
|
||||
va_end(va);
|
||||
|
||||
return string_append_c_str_len(this, buf, res);
|
||||
}
|
||||
#pragma endregion Member Mapping
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
|
||||
forceinline char* string_begin(String str) { return ((char*) str); }
|
||||
forceinline char* string_end (String str) { return ((char*) str + string_length(str)); }
|
||||
forceinline char* string_next (String str, char const* iter) { return ((char*) iter + 1); }
|
||||
|
||||
#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP
|
||||
forceinline char* begin(String str) { return ((char*) str); }
|
||||
forceinline char* end (String str) { return ((char*) str + string_length(str)); }
|
||||
forceinline char* next (String str, char* iter) { return ((char*) iter + 1); }
|
||||
#endif
|
||||
|
||||
#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP
|
||||
forceinline bool make_space_for(String& str, char const* to_append, ssize add_len);
|
||||
forceinline bool append(String& str, char c);
|
||||
forceinline bool append(String& str, char const* str_to_append);
|
||||
forceinline bool append(String& str, char const* str_to_append, ssize length);
|
||||
forceinline bool append(String& str, StrC str_to_append);
|
||||
forceinline bool append(String& str, const String other);
|
||||
forceinline bool append_fmt(String& str, char const* fmt, ...);
|
||||
forceinline char& back(String& str);
|
||||
forceinline void clear(String& str);
|
||||
forceinline void free(String& str);
|
||||
#endif
|
||||
|
||||
forceinline
|
||||
usize string_grow_formula(usize value) {
|
||||
// Using a very aggressive growth formula to reduce time mem_copying with recursive calls to append in this library.
|
||||
return 4 * value + 8;
|
||||
}
|
||||
|
||||
static
|
||||
String make( AllocatorInfo allocator, char const* str )
|
||||
{
|
||||
forceinline
|
||||
String string_make_c_str(AllocatorInfo allocator, char const* str) {
|
||||
ssize length = str ? str_len(str) : 0;
|
||||
return make_length( allocator, str, length );
|
||||
return string_make_length(allocator, str, length);
|
||||
}
|
||||
|
||||
static
|
||||
String make( AllocatorInfo allocator, StrC str )
|
||||
{
|
||||
return make_length( allocator, str.Ptr, str.Len );
|
||||
forceinline
|
||||
String string_make_strc(AllocatorInfo allocator, StrC str) {
|
||||
return string_make_length(allocator, str.Ptr, str.Len);
|
||||
}
|
||||
|
||||
static
|
||||
String make_reserve( AllocatorInfo allocator, ssize capacity );
|
||||
inline
|
||||
String string_fmt(AllocatorInfo allocator, char* buf, ssize buf_size, char const* fmt, ...) {
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
ssize res = str_fmt_va(buf, buf_size, fmt, va) - 1;
|
||||
va_end(va);
|
||||
|
||||
static
|
||||
String make_length( AllocatorInfo allocator, char const* str, ssize length );
|
||||
return string_make_length(allocator, buf, res);
|
||||
}
|
||||
|
||||
static
|
||||
String fmt( AllocatorInfo allocator, char* buf, ssize buf_size, char const* fmt, ... );
|
||||
|
||||
static
|
||||
String fmt_buf( AllocatorInfo allocator, char const* fmt, ... );
|
||||
|
||||
static
|
||||
String join( AllocatorInfo allocator, char const** parts, ssize num_parts, char const* glue )
|
||||
inline
|
||||
String string_fmt_buf(AllocatorInfo allocator, char const* fmt, ...)
|
||||
{
|
||||
String result = make( allocator, "" );
|
||||
local_persist thread_local
|
||||
PrintF_Buffer buf = struct_init(PrintF_Buffer, {0});
|
||||
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
ssize res = str_fmt_va(buf, GEN_PRINTF_MAXLEN, fmt, va) -1;
|
||||
va_end(va);
|
||||
|
||||
return string_make_length(allocator, buf, res);
|
||||
}
|
||||
|
||||
inline
|
||||
String string_join(AllocatorInfo allocator, char const** parts, ssize num_parts, char const* glue)
|
||||
{
|
||||
String result = string_make_c_str(allocator, "");
|
||||
|
||||
for (ssize idx = 0; idx < num_parts; ++idx)
|
||||
{
|
||||
result.append( parts[ idx ] );
|
||||
string_append_c_str(& result, parts[idx]);
|
||||
|
||||
if (idx < num_parts - 1)
|
||||
result.append( glue );
|
||||
string_append_c_str(& result, glue);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static
|
||||
bool are_equal( String lhs, String rhs )
|
||||
forceinline
|
||||
bool string_append_char(String* str, char c) {
|
||||
GEN_ASSERT(str != nullptr);
|
||||
return string_append_c_str_len( str, (char const*)& c, (ssize)1);
|
||||
}
|
||||
|
||||
forceinline
|
||||
bool string_append_c_str(String* str, char const* str_to_append) {
|
||||
GEN_ASSERT(str != nullptr);
|
||||
return string_append_c_str_len(str, str_to_append, str_len(str_to_append));
|
||||
}
|
||||
|
||||
inline
|
||||
bool string_append_c_str_len(String* str, char const* str_to_append, ssize append_length)
|
||||
{
|
||||
if ( lhs.length() != rhs.length() )
|
||||
GEN_ASSERT(str != nullptr);
|
||||
if ( rcast(sptr, str_to_append) > 0)
|
||||
{
|
||||
ssize curr_len = string_length(* str);
|
||||
|
||||
if ( ! string_make_space_for(str, str_to_append, append_length))
|
||||
return false;
|
||||
|
||||
for ( ssize idx = 0; idx < lhs.length(); ++idx )
|
||||
StringHeader* header = string_get_header(* str);
|
||||
|
||||
char* Data = * str;
|
||||
mem_copy( Data + curr_len, str_to_append, append_length);
|
||||
|
||||
Data[curr_len + append_length] = '\0';
|
||||
|
||||
header->Length = curr_len + append_length;
|
||||
}
|
||||
return str_to_append != nullptr;
|
||||
}
|
||||
|
||||
forceinline
|
||||
bool string_append_strc(String* str, StrC str_to_append) {
|
||||
GEN_ASSERT(str != nullptr);
|
||||
return string_append_c_str_len(str, str_to_append.Ptr, str_to_append.Len);
|
||||
}
|
||||
|
||||
forceinline
|
||||
bool string_append_string(String* str, String const other) {
|
||||
GEN_ASSERT(str != nullptr);
|
||||
return string_append_c_str_len(str, (char const*)other, string_length(other));
|
||||
}
|
||||
|
||||
bool string_append_fmt(String* str, char const* fmt, ...) {
|
||||
GEN_ASSERT(str != nullptr);
|
||||
ssize res;
|
||||
char buf[GEN_PRINTF_MAXLEN] = { 0 };
|
||||
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
res = str_fmt_va(buf, count_of(buf) - 1, fmt, va) - 1;
|
||||
va_end(va);
|
||||
|
||||
return string_append_c_str_len(str, (char const*)buf, res);
|
||||
}
|
||||
|
||||
inline
|
||||
bool string_are_equal_string(String const lhs, String const rhs)
|
||||
{
|
||||
if (string_length(lhs) != string_length(rhs))
|
||||
return false;
|
||||
|
||||
for (ssize idx = 0; idx < string_length(lhs); ++idx)
|
||||
if (lhs[idx] != rhs[idx])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static
|
||||
bool are_equal( String lhs, StrC rhs )
|
||||
inline
|
||||
bool string_are_equal_strc(String const lhs, StrC rhs)
|
||||
{
|
||||
if ( lhs.length() != (rhs.Len) )
|
||||
if (string_length(lhs) != (rhs.Len))
|
||||
return false;
|
||||
|
||||
for ( ssize idx = 0; idx < lhs.length(); ++idx )
|
||||
if ( lhs[idx] != rhs[idx] )
|
||||
for (ssize idx = 0; idx < string_length(lhs); ++idx)
|
||||
if (lhs[idx] != rhs.Ptr[idx])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool make_space_for( char const* str, ssize add_len );
|
||||
|
||||
bool append( char c )
|
||||
{
|
||||
return append( & c, 1 );
|
||||
forceinline
|
||||
ssize string_avail_space(String const str) {
|
||||
StringHeader const* header = rcast(StringHeader const*, scast(char const*, str) - sizeof(StringHeader));
|
||||
return header->Capacity - header->Length;
|
||||
}
|
||||
|
||||
bool append( char const* str )
|
||||
{
|
||||
return append( str, str_len( str ) );
|
||||
forceinline
|
||||
char* string_back(String str) {
|
||||
return & (str)[string_length(str) - 1];
|
||||
}
|
||||
|
||||
bool append( char const* str, ssize length )
|
||||
inline
|
||||
bool string_contains_StrC(String const str, StrC substring)
|
||||
{
|
||||
if ( sptr(str) > 0 )
|
||||
{
|
||||
ssize curr_len = this->length();
|
||||
StringHeader const* header = rcast(StringHeader const*, scast(char const*, str) - sizeof(StringHeader));
|
||||
|
||||
if ( ! make_space_for( str, length ) )
|
||||
if (substring.Len > header->Length)
|
||||
return false;
|
||||
|
||||
Header& header = get_header();
|
||||
ssize main_len = header->Length;
|
||||
ssize sub_len = substring.Len;
|
||||
|
||||
mem_copy( Data + curr_len, str, length );
|
||||
|
||||
Data[ curr_len + length ] = '\0';
|
||||
|
||||
header.Length = curr_len + length;
|
||||
}
|
||||
return str != nullptr;
|
||||
}
|
||||
|
||||
bool append( StrC str)
|
||||
for (ssize idx = 0; idx <= main_len - sub_len; ++idx)
|
||||
{
|
||||
return append( str.Ptr, str.Len );
|
||||
if (str_compare_len(str + idx, substring.Ptr, sub_len) == 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool append( const String other )
|
||||
{
|
||||
return append( other.Data, other.length() );
|
||||
return false;
|
||||
}
|
||||
|
||||
bool append_fmt( char const* fmt, ... );
|
||||
|
||||
ssize avail_space() const
|
||||
inline
|
||||
bool string_contains_string(String const str, String const substring)
|
||||
{
|
||||
Header const&
|
||||
header = * rcast( Header const*, Data - sizeof( Header ));
|
||||
StringHeader const* header = rcast(StringHeader const*, scast(char const*, str) - sizeof(StringHeader));
|
||||
|
||||
return header.Capacity - header.Length;
|
||||
if (string_length(substring) > header->Length)
|
||||
return false;
|
||||
|
||||
ssize main_len = header->Length;
|
||||
ssize sub_len = string_length(substring);
|
||||
|
||||
for (ssize idx = 0; idx <= main_len - sub_len; ++idx)
|
||||
{
|
||||
if (str_compare_len(str + idx, substring, sub_len) == 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
char& back()
|
||||
{
|
||||
return Data[ length() - 1 ];
|
||||
return false;
|
||||
}
|
||||
|
||||
ssize capacity() const
|
||||
{
|
||||
Header const&
|
||||
header = * rcast( Header const*, Data - sizeof( Header ));
|
||||
|
||||
return header.Capacity;
|
||||
forceinline
|
||||
ssize string_capacity(String const str) {
|
||||
StringHeader const* header = rcast(StringHeader const*, scast(char const*, str) - sizeof(StringHeader));
|
||||
return header->Capacity;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
get_header().Length = 0;
|
||||
forceinline
|
||||
void string_clear(String str) {
|
||||
string_get_header(str)->Length = 0;
|
||||
}
|
||||
|
||||
String duplicate( AllocatorInfo allocator ) const
|
||||
{
|
||||
return make_length( allocator, Data, length() );
|
||||
forceinline
|
||||
String string_duplicate(String const str, AllocatorInfo allocator) {
|
||||
return string_make_length(allocator, str, string_length(str));
|
||||
}
|
||||
|
||||
void free()
|
||||
{
|
||||
if ( ! Data )
|
||||
forceinline
|
||||
void string_free(String* str) {
|
||||
GEN_ASSERT(str != nullptr);
|
||||
if (! (* str))
|
||||
return;
|
||||
|
||||
Header& header = get_header();
|
||||
|
||||
gen::free( header.Allocator, & header );
|
||||
StringHeader* header = string_get_header(* str);
|
||||
allocator_free(header->Allocator, header);
|
||||
}
|
||||
|
||||
Header& get_header()
|
||||
{
|
||||
return *(Header*)(Data - sizeof(Header));
|
||||
forceinline
|
||||
StringHeader* string_get_header(String str) {
|
||||
return (StringHeader*)(scast(char*, str) - sizeof(StringHeader));
|
||||
}
|
||||
|
||||
ssize length() const
|
||||
forceinline
|
||||
ssize string_length(String const str)
|
||||
{
|
||||
Header const&
|
||||
header = * rcast( Header const*, Data - sizeof( Header ));
|
||||
|
||||
return header.Length;
|
||||
StringHeader const* header = rcast(StringHeader const*, scast(char const*, str) - sizeof(StringHeader));
|
||||
return header->Length;
|
||||
}
|
||||
|
||||
b32 starts_with( StrC substring ) const
|
||||
inline
|
||||
bool string_make_space_for(String* str, char const* to_append, ssize add_len)
|
||||
{
|
||||
if (substring.Len > length())
|
||||
ssize available = string_avail_space(* str);
|
||||
|
||||
if (available >= add_len) {
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ssize new_len, old_size, new_size;
|
||||
void* ptr;
|
||||
void* new_ptr;
|
||||
|
||||
AllocatorInfo allocator = string_get_header(* str)->Allocator;
|
||||
StringHeader* header = nullptr;
|
||||
|
||||
new_len = string_grow_formula(string_length(* str) + add_len);
|
||||
ptr = string_get_header(* str);
|
||||
old_size = size_of(StringHeader) + string_length(* str) + 1;
|
||||
new_size = size_of(StringHeader) + new_len + 1;
|
||||
|
||||
new_ptr = resize(allocator, ptr, old_size, new_size);
|
||||
|
||||
if (new_ptr == nullptr)
|
||||
return false;
|
||||
|
||||
b32 result = str_compare(Data, substring.Ptr, substring.Len ) == 0;
|
||||
header = rcast(StringHeader*, new_ptr);
|
||||
header->Allocator = allocator;
|
||||
header->Capacity = new_len;
|
||||
|
||||
char** Data = rcast(char**, str);
|
||||
* Data = rcast(char*, header + 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
forceinline
|
||||
b32 string_starts_with_strc(String const str, StrC substring) {
|
||||
if (substring.Len > string_length(str))
|
||||
return false;
|
||||
|
||||
b32 result = str_compare_len(str, substring.Ptr, substring.Len) == 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
b32 starts_with( String substring ) const
|
||||
{
|
||||
if (substring.length() > length())
|
||||
forceinline
|
||||
b32 string_starts_with_string(String const str, String substring) {
|
||||
if (string_length(substring) > string_length(str))
|
||||
return false;
|
||||
|
||||
b32 result = str_compare(Data, substring, substring.length() - 1 ) == 0;
|
||||
b32 result = str_compare_len(str, substring, string_length(substring) - 1) == 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
void skip_line()
|
||||
inline
|
||||
void string_skip_line(String str)
|
||||
{
|
||||
#define current (*scanner)
|
||||
char* scanner = Data;
|
||||
while ( current != '\r' && current != '\n' )
|
||||
{
|
||||
char* scanner = str;
|
||||
while (current != '\r' && current != '\n') {
|
||||
++scanner;
|
||||
}
|
||||
|
||||
s32 new_length = scanner - Data;
|
||||
s32 new_length = scanner - str;
|
||||
|
||||
if ( current == '\r' )
|
||||
{
|
||||
if (current == '\r') {
|
||||
new_length += 1;
|
||||
}
|
||||
|
||||
mem_move( Data, scanner, new_length );
|
||||
mem_move((char*)str, scanner, new_length);
|
||||
|
||||
Header* header = & get_header();
|
||||
StringHeader* header = string_get_header(str);
|
||||
header->Length = new_length;
|
||||
#undef current
|
||||
}
|
||||
|
||||
void strip_space()
|
||||
inline
|
||||
void strip_space(String str)
|
||||
{
|
||||
char* write_pos = Data;
|
||||
char* read_pos = Data;
|
||||
char* write_pos = str;
|
||||
char* read_pos = str;
|
||||
|
||||
while (* read_pos)
|
||||
{
|
||||
@@ -264,19 +613,25 @@ struct String
|
||||
}
|
||||
read_pos++;
|
||||
}
|
||||
|
||||
write_pos[0] = '\0'; // Null-terminate the modified string
|
||||
|
||||
// Update the length if needed
|
||||
get_header().Length = write_pos - Data;
|
||||
string_get_header(str)->Length = write_pos - str;
|
||||
}
|
||||
|
||||
void trim( char const* cut_set )
|
||||
forceinline
|
||||
StrC string_to_strc(String str) {
|
||||
StrC result = { string_length(str), (char const*)str };
|
||||
return result;
|
||||
}
|
||||
|
||||
inline
|
||||
void trim(String str, char const* cut_set)
|
||||
{
|
||||
ssize len = 0;
|
||||
|
||||
char* start_pos = Data;
|
||||
char* end_pos = Data + length() - 1;
|
||||
char* start_pos = str;
|
||||
char* end_pos = scast(char*, str) + string_length(str) - 1;
|
||||
|
||||
while (start_pos <= end_pos && char_first_occurence(cut_set, *start_pos))
|
||||
start_pos++;
|
||||
@@ -286,130 +641,104 @@ struct String
|
||||
|
||||
len = scast(ssize, (start_pos > end_pos) ? 0 : ((end_pos - start_pos) + 1));
|
||||
|
||||
if ( Data != start_pos )
|
||||
mem_move( Data, start_pos, len );
|
||||
if (str != start_pos)
|
||||
mem_move(str, start_pos, len);
|
||||
|
||||
Data[ len ] = '\0';
|
||||
str[len] = '\0';
|
||||
|
||||
get_header().Length = len;
|
||||
string_get_header(str)->Length = len;
|
||||
}
|
||||
|
||||
void trim_space()
|
||||
{
|
||||
return trim( " \t\r\n\v\f" );
|
||||
forceinline
|
||||
void trim_space(String str) {
|
||||
trim(str, " \t\r\n\v\f");
|
||||
}
|
||||
|
||||
// Debug function that provides a copy of the string with whitespace characters visualized.
|
||||
String visualize_whitespace() const
|
||||
inline
|
||||
String visualize_whitespace(String const str)
|
||||
{
|
||||
Header* header = (Header*)(Data - sizeof(Header));
|
||||
StringHeader* header = (StringHeader*)(scast(char const*, str) - sizeof(StringHeader));
|
||||
String result = string_make_reserve(header->Allocator, string_length(str) * 2); // Assume worst case for space requirements.
|
||||
|
||||
String result = make_reserve(header->Allocator, length() * 2); // Assume worst case for space requirements.
|
||||
|
||||
for ( char c : *this )
|
||||
{
|
||||
switch ( c )
|
||||
for (char const* c = string_begin(str); c != string_end(str); c = string_next(str, c))
|
||||
switch ( * c )
|
||||
{
|
||||
case ' ':
|
||||
result.append( txt("·") );
|
||||
string_append_strc(& result, txt("·"));
|
||||
break;
|
||||
case '\t':
|
||||
result.append( txt("→") );
|
||||
string_append_strc(& result, txt("→"));
|
||||
break;
|
||||
case '\n':
|
||||
result.append( txt("↵") );
|
||||
string_append_strc(& result, txt("↵"));
|
||||
break;
|
||||
case '\r':
|
||||
result.append( txt("⏎") );
|
||||
string_append_strc(& result, txt("⏎"));
|
||||
break;
|
||||
case '\v':
|
||||
result.append( txt("⇕") );
|
||||
string_append_strc(& result, txt("⇕"));
|
||||
break;
|
||||
case '\f':
|
||||
result.append( txt("⌂") );
|
||||
string_append_strc(& result, txt("⌂"));
|
||||
break;
|
||||
default:
|
||||
result.append(c);
|
||||
string_append_char(& result, * c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#pragma endregion String
|
||||
|
||||
// For-range support
|
||||
|
||||
char* begin() const
|
||||
{
|
||||
return Data;
|
||||
}
|
||||
|
||||
char* end() const
|
||||
{
|
||||
Header const&
|
||||
header = * rcast( Header const*, Data - sizeof( Header ));
|
||||
|
||||
return Data + header.Length;
|
||||
}
|
||||
|
||||
operator bool()
|
||||
{
|
||||
return Data != nullptr;
|
||||
}
|
||||
|
||||
operator char* ()
|
||||
{
|
||||
return Data;
|
||||
}
|
||||
|
||||
operator char const* () const
|
||||
{
|
||||
return Data;
|
||||
}
|
||||
|
||||
operator StrC() const
|
||||
{
|
||||
return { length(), Data };
|
||||
}
|
||||
|
||||
// Used with cached strings
|
||||
// Essentially makes the string a string view.
|
||||
String const& operator = ( String const& other ) const
|
||||
{
|
||||
if ( this == & other )
|
||||
return *this;
|
||||
|
||||
String*
|
||||
this_ = ccast(String*, this);
|
||||
this_->Data = other.Data;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
char& operator [] ( ssize index )
|
||||
{
|
||||
return Data[ index ];
|
||||
}
|
||||
|
||||
char const& operator [] ( ssize index ) const
|
||||
{
|
||||
return Data[ index ];
|
||||
}
|
||||
|
||||
char* Data;
|
||||
};
|
||||
|
||||
struct String_POD
|
||||
{
|
||||
#if GEN_COMPILER_CPP
|
||||
struct String_POD {
|
||||
char* Data;
|
||||
};
|
||||
static_assert( sizeof( String_POD ) == sizeof( String ), "String is not a POD" );
|
||||
#endif
|
||||
|
||||
// Implements basic string interning. Data structure is based off the ZPL Hashtable.
|
||||
using StringTable = HashTable<String const>;
|
||||
forceinline
|
||||
StrC strc_duplicate(StrC str, AllocatorInfo allocator) {
|
||||
StrC result = string_to_strc( string_make_length(allocator, str.Ptr, str.Len));
|
||||
return result;
|
||||
}
|
||||
|
||||
inline
|
||||
StrC strc_visualize_whitespace(StrC str, AllocatorInfo allocator)
|
||||
{
|
||||
String result = string_make_reserve(allocator, str.Len * 2); // Assume worst case for space requirements.
|
||||
for (char const* c = strc_begin(str); c != strc_end(str); c = strc_next(str, c))
|
||||
switch ( * c )
|
||||
{
|
||||
case ' ':
|
||||
string_append_strc(& result, txt("·"));
|
||||
break;
|
||||
case '\t':
|
||||
string_append_strc(& result, txt("→"));
|
||||
break;
|
||||
case '\n':
|
||||
string_append_strc(& result, txt("↵"));
|
||||
break;
|
||||
case '\r':
|
||||
string_append_strc(& result, txt("⏎"));
|
||||
break;
|
||||
case '\v':
|
||||
string_append_strc(& result, txt("⇕"));
|
||||
break;
|
||||
case '\f':
|
||||
string_append_strc(& result, txt("⌂"));
|
||||
break;
|
||||
default:
|
||||
string_append_char(& result, * c);
|
||||
break;
|
||||
}
|
||||
return string_to_strc(result);
|
||||
}
|
||||
|
||||
// Represents strings cached with the string table.
|
||||
// Should never be modified, if changed string is desired, cache_string( str ) another.
|
||||
using StringCached = String const;
|
||||
typedef StrC StringCached;
|
||||
|
||||
// Implements basic string interning. Data structure is based off the ZPL Hashtable.
|
||||
typedef HashTable(StringCached) StringTable;
|
||||
#pragma endregion Strings
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
Invalid
|
||||
Untyped
|
||||
NewLine
|
||||
Comment
|
||||
Access_Private
|
||||
Access_Protected
|
||||
Access_Public
|
||||
PlatformAttributes
|
||||
Class
|
||||
Class_Fwd
|
||||
Class_Body
|
||||
Constructor
|
||||
Constructor_Fwd
|
||||
Destructor
|
||||
Destructor_Fwd
|
||||
Enum
|
||||
Enum_Fwd
|
||||
Enum_Body
|
||||
Enum_Class
|
||||
Enum_Class_Fwd
|
||||
Execution
|
||||
Export_Body
|
||||
Extern_Linkage
|
||||
Extern_Linkage_Body
|
||||
Friend
|
||||
Function
|
||||
Function_Fwd
|
||||
Function_Body
|
||||
Global_Body
|
||||
Module
|
||||
Namespace
|
||||
Namespace_Body
|
||||
Operator
|
||||
Operator_Fwd
|
||||
Operator_Member
|
||||
Operator_Member_Fwd
|
||||
Operator_Cast
|
||||
Operator_Cast_Fwd
|
||||
Parameters
|
||||
Preprocess_Define
|
||||
Preprocess_Include
|
||||
Preprocess_If
|
||||
Preprocess_IfDef
|
||||
Preprocess_IfNotDef
|
||||
Preprocess_ElIf
|
||||
Preprocess_Else
|
||||
Preprocess_EndIf
|
||||
Preprocess_Pragma
|
||||
Specifiers
|
||||
Struct
|
||||
Struct_Fwd
|
||||
Struct_Body
|
||||
Template
|
||||
Typedef
|
||||
Typename
|
||||
Union
|
||||
Union_Body
|
||||
Using
|
||||
Using_Namespace
|
||||
Variable
|
||||
|
@@ -0,0 +1,61 @@
|
||||
Invalid, "__NA__"
|
||||
Untyped, "__NA__"
|
||||
NewLine, "__NA__"
|
||||
Comment, "//"
|
||||
Access_Private, "private"
|
||||
Access_Protected, "protected"
|
||||
Access_Public, "public"
|
||||
PlatformAttributes, "__NA__"
|
||||
Class, "class"
|
||||
Class_Fwd, "clsss"
|
||||
Class_Body, "__NA__"
|
||||
Constructor, "__NA__"
|
||||
Constructor_Fwd, "__NA__"
|
||||
Destructor, "__NA__"
|
||||
Destructor_Fwd, "__NA__"
|
||||
Enum, "enum"
|
||||
Enum_Fwd, "enum"
|
||||
Enum_Body, "__NA__"
|
||||
Enum_Class, "enum class"
|
||||
Enum_Class_Fwd, "enum class"
|
||||
Execution, "__NA__"
|
||||
Export_Body, "__NA__"
|
||||
Extern_Linkage, "extern"
|
||||
Extern_Linkage_Body, "extern"
|
||||
Friend, "friend"
|
||||
Function, "__NA__"
|
||||
Function_Fwd, "__NA__"
|
||||
Function_Body, "__NA__"
|
||||
Global_Body, "__NA__"
|
||||
Module, "module"
|
||||
Namespace, "namespace"
|
||||
Namespace_Body, "__NA__"
|
||||
Operator, "operator"
|
||||
Operator_Fwd, "operator"
|
||||
Operator_Member, "operator"
|
||||
Operator_Member_Fwd, "operator"
|
||||
Operator_Cast, "operator"
|
||||
Operator_Cast_Fwd, "operator"
|
||||
Parameters, "__NA__"
|
||||
Preprocess_Define, "define"
|
||||
Preprocess_Include, "include"
|
||||
Preprocess_If, "if"
|
||||
Preprocess_IfDef, "ifdef"
|
||||
Preprocess_IfNotDef, "ifndef"
|
||||
Preprocess_ElIf, "elif"
|
||||
Preprocess_Else, "else"
|
||||
Preprocess_EndIf, "endif"
|
||||
Preprocess_Pragma, "pragma"
|
||||
Specifiers, "__NA__"
|
||||
Struct, "struct"
|
||||
Struct_Fwd, "struct"
|
||||
Struct_Body, "__NA__"
|
||||
Template, "template"
|
||||
Typedef, "typedef"
|
||||
Typename, "__NA__"
|
||||
Union, "union"
|
||||
Union_Fwd, "union"
|
||||
Union_Body, "__NA__"
|
||||
Using, "using"
|
||||
Using_Namespace, "using namespace"
|
||||
Variable, "__NA__"
|
||||
|
@@ -8,6 +8,13 @@
|
||||
|
||||
#include "gen.hpp"
|
||||
|
||||
// These are intended for use in the base library of gencpp and the C-variant of the library
|
||||
// It provides a interoperability between the C++ and C interfacing for containers. (not letting these do any crazy substiution though)
|
||||
// They are undefined in gen.hpp and gen.cpp at the end of the files.
|
||||
// We cpp library expects the user to use the regular calls as they can resolve the type fine.
|
||||
|
||||
#include "helpers/push_container_defines.inline.hpp"
|
||||
|
||||
//! If its desired to roll your own dependencies, define GEN_ROLL_OWN_DEPENDENCIES before including this file.
|
||||
//! Dependencies are derived from the c-zpl library: https://github.com/zpl-c/zpl
|
||||
#ifndef GEN_ROLL_OWN_DEPENDENCIES
|
||||
@@ -32,4 +39,5 @@ GEN_NS_BEGIN
|
||||
|
||||
GEN_NS_END
|
||||
|
||||
#include "helpers/pop_container_defines.inline.hpp"
|
||||
#include "helpers/pop_ignores.inline.hpp"
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
#include "helpers/push_ignores.inline.hpp"
|
||||
#include "components/header_start.hpp"
|
||||
|
||||
// Has container defines pushed
|
||||
#include "gen.dep.hpp"
|
||||
|
||||
GEN_NS_BEGIN
|
||||
|
||||
#include "components/types.hpp"
|
||||
@@ -30,4 +33,5 @@ GEN_NS_BEGIN
|
||||
|
||||
GEN_NS_END
|
||||
|
||||
#include "helpers/pop_container_defines.inline.hpp"
|
||||
#include "helpers/pop_ignores.inline.hpp"
|
||||
|
||||
+307
-200
@@ -8,58 +8,110 @@ GEN_NS_END
|
||||
|
||||
using namespace gen;
|
||||
|
||||
CodeBody gen_ecode( char const* path )
|
||||
CodeBody gen_ecode( char const* path, bool use_c_definition = false )
|
||||
{
|
||||
char scratch_mem[kilobytes(1)];
|
||||
Arena scratch = Arena::init_from_memory( scratch_mem, sizeof(scratch_mem) );
|
||||
char scratch_mem[kilobytes(4)];
|
||||
Arena scratch = arena_init_from_memory( scratch_mem, sizeof(scratch_mem) );
|
||||
|
||||
file_read_contents( scratch, zero_terminate, path );
|
||||
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;
|
||||
|
||||
String enum_entries = String::make_reserve( GlobalAllocator, kilobytes(1) );
|
||||
String to_str_entries = String::make_reserve( GlobalAllocator, kilobytes(1) );
|
||||
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 ( ADT_Node node : enum_strs )
|
||||
for ( ssize idx = 0; idx < array_num(enum_strs); ++ idx )
|
||||
{
|
||||
char const* code = node.string;
|
||||
enum_entries.append_fmt( "%s,\n", code );
|
||||
to_str_entries.append_fmt( "{ sizeof(\"%s\"), \"%s\" },\n", code, code );
|
||||
char const* code = enum_strs [idx].string;
|
||||
char const* keyword = keyword_strs[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 = parse_enum(gen::token_fmt_impl((3 + 1) / 2, "entries", (StrC)enum_entries, "enum Type : u32 { <entries> NumTypes };"));
|
||||
CodeEnum enum_code;
|
||||
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
|
||||
{
|
||||
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 };"
|
||||
));
|
||||
}
|
||||
|
||||
#pragma push_macro("local_persist")
|
||||
#undef local_persist
|
||||
CodeFn to_str = parse_function( token_fmt( "entries", (StrC)to_str_entries, stringize(
|
||||
StrC lookup_size = string_to_strc(string_fmt_buf(GlobalAllocator, "%d", array_num(enum_strs) ));
|
||||
CodeBody to_str_fns = parse_global_body( token_fmt(
|
||||
"entries", string_to_strc(to_str_entries)
|
||||
, "keywords", string_to_strc(to_keyword_str_entries)
|
||||
, "num", lookup_size
|
||||
, stringize(
|
||||
inline
|
||||
StrC to_str( Type type )
|
||||
StrC codetype_to_str( CodeType type )
|
||||
{
|
||||
local_persist
|
||||
StrC lookup[] {
|
||||
StrC lookup[<num>] = {
|
||||
<entries>
|
||||
};
|
||||
return lookup[ type ];
|
||||
}
|
||||
|
||||
inline
|
||||
StrC codetype_to_keyword_str( CodeType type )
|
||||
{
|
||||
local_persist
|
||||
StrC lookup[ <num> ] = {
|
||||
<keywords>
|
||||
};
|
||||
return lookup[ type ];
|
||||
}
|
||||
)));
|
||||
#pragma pop_macro("local_persist")
|
||||
|
||||
CodeNS nspace = def_namespace( name(ECode), def_namespace_body( args( enum_code, to_str ) ) );
|
||||
CodeUsing code_t = def_using( name(CodeT), def_type( name(ECode::Type) ) );
|
||||
CodeBody result = def_body(CT_Global_Body);
|
||||
body_append(result, enum_code);
|
||||
|
||||
return def_global_body( args( nspace, code_t, fmt_newline ) );
|
||||
if (use_c_definition)
|
||||
{
|
||||
CodeTypedef code_t = parse_typedef(code(typedef enum CodeType CodeType; ));
|
||||
body_append(result, code_t);
|
||||
}
|
||||
|
||||
CodeBody gen_eoperator( char const* path )
|
||||
body_append(result, to_str_fns);
|
||||
|
||||
if (! use_c_definition)
|
||||
{
|
||||
#pragma push_macro("forceinline")
|
||||
#undef forceinline
|
||||
CodeBody alias_mappings = parse_global_body(code(
|
||||
forceinline StrC to_str (CodeType type) { return codetype_to_str(type); }
|
||||
forceinline StrC to_keyword_str(CodeType type) { return codetype_to_keyword_str(type); }
|
||||
));
|
||||
#pragma pop_macro("forceinline")
|
||||
body_append(result, alias_mappings);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
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) );
|
||||
Arena scratch = arena_init_from_memory( scratch_mem, sizeof(scratch_mem) );
|
||||
|
||||
file_read_contents( scratch, zero_terminate, path );
|
||||
file_read_contents( arena_allocator_info(& scratch), file_zero_terminate, path );
|
||||
|
||||
CSV_Object csv_nodes;
|
||||
csv_parse( &csv_nodes, scratch_mem, GlobalAllocator, false );
|
||||
@@ -67,34 +119,57 @@ CodeBody gen_eoperator( char const* path )
|
||||
Array<ADT_Node> enum_strs = csv_nodes.nodes[0].nodes;
|
||||
Array<ADT_Node> str_strs = csv_nodes.nodes[1].nodes;
|
||||
|
||||
String enum_entries = String::make_reserve( GlobalAllocator, kilobytes(1) );
|
||||
String to_str_entries = String::make_reserve( GlobalAllocator, kilobytes(1) );
|
||||
String enum_entries = string_make_reserve( GlobalAllocator, kilobytes(1) );
|
||||
String to_str_entries = string_make_reserve( GlobalAllocator, kilobytes(1) );
|
||||
|
||||
for (usize idx = 0; idx < enum_strs.num(); idx++)
|
||||
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;
|
||||
|
||||
enum_entries.append_fmt( "%s,\n", enum_str );
|
||||
to_str_entries.append_fmt( "{ sizeof(\"%s\"), \"%s\" },\n", entry_to_str, entry_to_str);
|
||||
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);
|
||||
}
|
||||
|
||||
CodeEnum enum_code = parse_enum(token_fmt("entries", (StrC)enum_entries, stringize(
|
||||
enum Type : u32
|
||||
CodeEnum enum_code;
|
||||
if (use_c_definition)
|
||||
{
|
||||
#pragma push_macro("enum_underlying")
|
||||
#undef enum_underlying
|
||||
enum_code = parse_enum(token_fmt("entries", string_to_strc(enum_entries), stringize(
|
||||
enum Operator enum_underlying(u32)
|
||||
{
|
||||
<entries>
|
||||
NumOps
|
||||
Op_NumOps,
|
||||
Op_UnderlyingType = GEN_U32_MAX
|
||||
};
|
||||
)));
|
||||
#pragma pop_macro("enum_underlying")
|
||||
}
|
||||
else
|
||||
{
|
||||
enum_code = parse_enum(token_fmt("entries", string_to_strc(enum_entries), stringize(
|
||||
enum Operator : u32
|
||||
{
|
||||
<entries>
|
||||
Op_NumOps,
|
||||
Op_UnderlyingType = GEN_U32_MAX
|
||||
};
|
||||
)));
|
||||
}
|
||||
|
||||
#pragma push_macro("local_persist")
|
||||
#undef local_persist
|
||||
CodeFn to_str = parse_function(token_fmt("entries", (StrC)to_str_entries, stringize(
|
||||
StrC lookup_size = string_to_strc(string_fmt_buf(GlobalAllocator, "%d", array_num(enum_strs) ));
|
||||
CodeFn to_str = parse_function(token_fmt(
|
||||
"entries", string_to_strc(to_str_entries)
|
||||
, "num", lookup_size
|
||||
, stringize(
|
||||
inline
|
||||
StrC to_str( Type op )
|
||||
StrC operator_to_str( Operator op )
|
||||
{
|
||||
local_persist
|
||||
StrC lookup[] {
|
||||
StrC lookup[<num>] = {
|
||||
<entries>
|
||||
};
|
||||
|
||||
@@ -103,19 +178,35 @@ CodeBody gen_eoperator( char const* path )
|
||||
)));
|
||||
#pragma pop_macro("local_persist")
|
||||
|
||||
CodeNS nspace = def_namespace( name(EOperator), def_namespace_body( args( enum_code, to_str ) ) );
|
||||
|
||||
CodeUsing operator_t = def_using( name(OperatorT), def_type( name(EOperator::Type) ) );
|
||||
|
||||
return def_global_body( args( nspace, operator_t, fmt_newline ) );
|
||||
CodeBody result = def_body(CT_Global_Body);
|
||||
body_append(result, enum_code);
|
||||
if ( use_c_definition )
|
||||
{
|
||||
CodeTypedef operator_t = parse_typedef(code( typedef enum Operator Operator; ));
|
||||
body_append(result, operator_t);
|
||||
}
|
||||
|
||||
CodeBody gen_especifier( char const* path )
|
||||
body_append(result, to_str);
|
||||
|
||||
if (! use_c_definition)
|
||||
{
|
||||
#pragma push_macro("forceinline")
|
||||
#undef forceinline
|
||||
CodeBody alias_mappings = parse_global_body(code(
|
||||
forceinline StrC to_str(Operator op) { return operator_to_str(op); }
|
||||
));
|
||||
#pragma pop_macro("forceinline")
|
||||
body_append(result, alias_mappings);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
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) );
|
||||
Arena scratch = arena_init_from_memory( scratch_mem, sizeof(scratch_mem) );
|
||||
|
||||
file_read_contents( scratch, zero_terminate, path );
|
||||
file_read_contents( arena_allocator_info(& scratch), file_zero_terminate, path );
|
||||
|
||||
CSV_Object csv_nodes;
|
||||
csv_parse( &csv_nodes, scratch_mem, GlobalAllocator, false );
|
||||
@@ -123,31 +214,50 @@ CodeBody gen_especifier( char const* path )
|
||||
Array<ADT_Node> enum_strs = csv_nodes.nodes[0].nodes;
|
||||
Array<ADT_Node> str_strs = csv_nodes.nodes[1].nodes;
|
||||
|
||||
String enum_entries = String::make_reserve( GlobalAllocator, kilobytes(1) );
|
||||
String to_str_entries = String::make_reserve( GlobalAllocator, kilobytes(1) );
|
||||
String enum_entries = string_make_reserve( GlobalAllocator, kilobytes(1) );
|
||||
String to_str_entries = string_make_reserve( GlobalAllocator, kilobytes(1) );
|
||||
|
||||
for (usize idx = 0; idx < enum_strs.num(); idx++)
|
||||
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;
|
||||
|
||||
enum_entries.append_fmt( "%s,\n", enum_str );
|
||||
to_str_entries.append_fmt( "{ sizeof(\"%s\"), \"%s\" },\n", entry_to_str, entry_to_str);
|
||||
string_append_fmt( & enum_entries, "Spec_%s,\n", enum_str );
|
||||
string_append_fmt( & to_str_entries, "{ sizeof(\"%s\"), \"%s\" },\n", entry_to_str, entry_to_str);
|
||||
}
|
||||
|
||||
CodeEnum enum_code = parse_enum(token_fmt("entries", (StrC)enum_entries, stringize(
|
||||
enum Type : u32
|
||||
CodeEnum enum_code;
|
||||
if (use_c_definition)
|
||||
{
|
||||
#pragma push_macro("enum_underlying")
|
||||
#undef enum_underlying
|
||||
enum_code = parse_enum(token_fmt("entries", string_to_strc(enum_entries), stringize(
|
||||
enum Specifier enum_underlying(u32)
|
||||
{
|
||||
<entries>
|
||||
NumSpecifiers
|
||||
Spec_NumSpecifiers,
|
||||
Spec_UnderlyingType = GEN_U32_MAX
|
||||
};
|
||||
)));
|
||||
|
||||
CodeFn is_trailing = parse_function(token_fmt("specifier", (StrC)to_str_entries, stringize(
|
||||
inline
|
||||
bool is_trailing( Type specifier )
|
||||
#pragma pop_macro("enum_underlying")
|
||||
}
|
||||
else
|
||||
{
|
||||
return specifier > Virtual;
|
||||
enum_code = parse_enum(token_fmt("entries", string_to_strc(enum_entries), stringize(
|
||||
enum Specifier : u32
|
||||
{
|
||||
<entries>
|
||||
Spec_NumSpecifiers,
|
||||
Spec_UnderlyingType = GEN_U32_MAX
|
||||
};
|
||||
)));
|
||||
}
|
||||
|
||||
CodeFn is_trailing = parse_function(token_fmt("specifier", string_to_strc(to_str_entries), stringize(
|
||||
inline
|
||||
bool spec_is_trailing( Specifier specifier )
|
||||
{
|
||||
return specifier > Spec_Virtual;
|
||||
}
|
||||
)));
|
||||
|
||||
@@ -161,12 +271,16 @@ CodeBody gen_especifier( char const* path )
|
||||
#undef do_once_end
|
||||
#undef forceinline
|
||||
#undef neverinline
|
||||
CodeFn to_str = parse_function(token_fmt("entries", (StrC)to_str_entries, stringize(
|
||||
StrC lookup_size = string_to_strc(string_fmt_buf(GlobalAllocator, "%d", array_num(enum_strs) ));
|
||||
CodeFn to_str = parse_function(token_fmt(
|
||||
"entries", string_to_strc(to_str_entries)
|
||||
, "num", lookup_size
|
||||
, stringize(
|
||||
inline
|
||||
StrC to_str( Type type )
|
||||
StrC spec_to_str( Specifier type )
|
||||
{
|
||||
local_persist
|
||||
StrC lookup[] {
|
||||
StrC lookup[<num>] = {
|
||||
<entries>
|
||||
};
|
||||
|
||||
@@ -174,16 +288,16 @@ CodeBody gen_especifier( char const* path )
|
||||
}
|
||||
)));
|
||||
|
||||
CodeFn to_type = parse_function( token_fmt( "entries", (StrC)to_str_entries, stringize(
|
||||
CodeFn to_type = parse_function( token_fmt( "entries", string_to_strc(to_str_entries), stringize(
|
||||
inline
|
||||
Type to_type( StrC str )
|
||||
Specifier strc_to_specifier( StrC str )
|
||||
{
|
||||
local_persist
|
||||
u32 keymap[ NumSpecifiers ];
|
||||
u32 keymap[ Spec_NumSpecifiers ];
|
||||
do_once_start
|
||||
for ( u32 index = 0; index < NumSpecifiers; index++ )
|
||||
for ( u32 index = 0; index < Spec_NumSpecifiers; index++ )
|
||||
{
|
||||
StrC enum_str = to_str( (Type)index );
|
||||
StrC enum_str = spec_to_str( (Specifier)index );
|
||||
|
||||
// We subtract 1 to remove the null terminator
|
||||
// This is because the tokens lexed are not null terminated.
|
||||
@@ -193,13 +307,13 @@ CodeBody gen_especifier( char const* path )
|
||||
|
||||
u32 hash = crc32( str.Ptr, str.Len );
|
||||
|
||||
for ( u32 index = 0; index < NumSpecifiers; index++ )
|
||||
for ( u32 index = 0; index < Spec_NumSpecifiers; index++ )
|
||||
{
|
||||
if ( keymap[index] == hash )
|
||||
return (Type)index;
|
||||
return (Specifier)index;
|
||||
}
|
||||
|
||||
return Invalid;
|
||||
return Spec_Invalid;
|
||||
}
|
||||
)));
|
||||
#pragma pop_macro("local_persist")
|
||||
@@ -208,24 +322,46 @@ CodeBody gen_especifier( char const* path )
|
||||
#pragma pop_macro("forceinline")
|
||||
#pragma pop_macro("neverinline")
|
||||
|
||||
CodeNS nspace = def_namespace( name(ESpecifier), def_namespace_body( args( enum_code, is_trailing, to_str, to_type ) ) );
|
||||
|
||||
CodeUsing specifier_t = def_using( name(SpecifierT), def_type( name(ESpecifier::Type) ) );
|
||||
|
||||
return def_global_body( args( nspace, specifier_t, fmt_newline ) );
|
||||
CodeBody result = def_body(CT_Global_Body);
|
||||
body_append(result, enum_code);
|
||||
if (use_c_definition)
|
||||
{
|
||||
CodeTypedef specifier_t = parse_typedef( code(typedef u32 Specifier; ));
|
||||
body_append(result, specifier_t);
|
||||
}
|
||||
|
||||
CodeBody gen_etoktype( char const* etok_path, char const* attr_path )
|
||||
body_append(result, to_str);
|
||||
body_append(result, is_trailing);
|
||||
body_append(result, to_type);
|
||||
|
||||
if (! use_c_definition)
|
||||
{
|
||||
#pragma push_macro("forceinline")
|
||||
#undef forceinline
|
||||
CodeBody alias_mappings = parse_global_body(code(
|
||||
forceinline StrC to_str (Specifier spec) { return spec_to_str(spec); }
|
||||
forceinline Specifier to_type( StrC str ) { return strc_to_specifier(str); }
|
||||
forceinline bool is_trailing( Specifier specifier ) { return spec_is_trailing(specifier); }
|
||||
));
|
||||
#pragma pop_macro("forceinline")
|
||||
body_append(result, alias_mappings);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
CodeBody gen_etoktype( char const* etok_path, char const* attr_path, bool use_c_definition = false )
|
||||
{
|
||||
char scratch_mem[kilobytes(16)];
|
||||
Arena scratch = Arena::init_from_memory( scratch_mem, sizeof(scratch_mem) );
|
||||
Arena scratch = arena_init_from_memory( scratch_mem, sizeof(scratch_mem) );
|
||||
|
||||
FileContents enum_content = file_read_contents( scratch, zero_terminate, etok_path );
|
||||
AllocatorInfo scratch_info = arena_allocator_info(& scratch);
|
||||
|
||||
FileContents enum_content = file_read_contents( scratch_info, file_zero_terminate, etok_path );
|
||||
|
||||
CSV_Object csv_enum_nodes;
|
||||
csv_parse( &csv_enum_nodes, rcast(char*, enum_content.data), GlobalAllocator, false );
|
||||
|
||||
FileContents attrib_content = file_read_contents( scratch, zero_terminate, attr_path );
|
||||
FileContents attrib_content = file_read_contents( scratch_info, file_zero_terminate, attr_path );
|
||||
|
||||
CSV_Object csv_attr_nodes;
|
||||
csv_parse( &csv_attr_nodes, rcast(char*, attrib_content.data), GlobalAllocator, false );
|
||||
@@ -235,50 +371,66 @@ CodeBody gen_etoktype( char const* etok_path, char const* attr_path )
|
||||
Array<ADT_Node> attribute_strs = csv_attr_nodes.nodes[0].nodes;
|
||||
Array<ADT_Node> attribute_str_strs = csv_attr_nodes.nodes[1].nodes;
|
||||
|
||||
String enum_entries = String::make_reserve( GlobalAllocator, kilobytes(2) );
|
||||
String to_str_entries = String::make_reserve( GlobalAllocator, kilobytes(4) );
|
||||
String attribute_entries = String::make_reserve( GlobalAllocator, kilobytes(2) );
|
||||
String to_str_attributes = String::make_reserve( GlobalAllocator, kilobytes(4) );
|
||||
String attribute_define_entries = String::make_reserve( GlobalAllocator, kilobytes(4) );
|
||||
String enum_entries = string_make_reserve( GlobalAllocator, kilobytes(2) );
|
||||
String to_str_entries = string_make_reserve( GlobalAllocator, kilobytes(4) );
|
||||
String attribute_entries = string_make_reserve( GlobalAllocator, kilobytes(2) );
|
||||
String to_str_attributes = string_make_reserve( GlobalAllocator, kilobytes(4) );
|
||||
String attribute_define_entries = string_make_reserve( GlobalAllocator, kilobytes(4) );
|
||||
|
||||
for (usize idx = 0; idx < enum_strs.num(); idx++)
|
||||
for (usize idx = 0; idx < array_num(enum_strs); idx++)
|
||||
{
|
||||
char const* enum_str = enum_strs[idx].string;
|
||||
char const* entry_to_str = enum_str_strs [idx].string;
|
||||
|
||||
enum_entries.append_fmt( "%s,\n", enum_str );
|
||||
to_str_entries.append_fmt( "{ sizeof(\"%s\"), \"%s\" },\n", entry_to_str, entry_to_str);
|
||||
string_append_fmt( & enum_entries, "Tok_%s,\n", enum_str );
|
||||
string_append_fmt( & to_str_entries, "{ sizeof(\"%s\"), \"%s\" },\n", entry_to_str, entry_to_str);
|
||||
}
|
||||
|
||||
for ( usize idx = 0; idx < attribute_strs.num(); idx++ )
|
||||
for ( usize idx = 0; idx < array_num(attribute_strs); idx++ )
|
||||
{
|
||||
char const* attribute_str = attribute_strs[idx].string;
|
||||
char const* entry_to_str = attribute_str_strs [idx].string;
|
||||
|
||||
attribute_entries.append_fmt( "Attribute_%s,\n", attribute_str );
|
||||
to_str_attributes.append_fmt( "{ sizeof(\"%s\"), \"%s\" },\n", entry_to_str, entry_to_str);
|
||||
attribute_define_entries.append_fmt( "Entry( Attribute_%s, \"%s\" )", attribute_str, entry_to_str );
|
||||
string_append_fmt( & attribute_entries, "Tok_Attribute_%s,\n", attribute_str );
|
||||
string_append_fmt( & to_str_attributes, "{ sizeof(\"%s\"), \"%s\" },\n", entry_to_str, entry_to_str);
|
||||
string_append_fmt( & attribute_define_entries, "Entry( Tok_Attribute_%s, \"%s\" )", attribute_str, entry_to_str );
|
||||
|
||||
if ( idx < attribute_strs.num() - 1 )
|
||||
attribute_define_entries.append( " \\\n");
|
||||
if ( idx < array_num(attribute_strs) - 1 )
|
||||
string_append_strc( & attribute_define_entries, txt(" \\\n"));
|
||||
else
|
||||
attribute_define_entries.append( "\n");
|
||||
string_append_strc( & attribute_define_entries, txt("\n"));
|
||||
}
|
||||
|
||||
#pragma push_macro("GEN_DEFINE_ATTRIBUTE_TOKENS")
|
||||
#undef GEN_DEFINE_ATTRIBUTE_TOKENS
|
||||
CodeDefine attribute_entires_def = def_define( name(GEN_DEFINE_ATTRIBUTE_TOKENS), attribute_define_entries );
|
||||
CodeDefine attribute_entires_def = def_define( name(GEN_DEFINE_ATTRIBUTE_TOKENS), string_to_strc(attribute_define_entries) );
|
||||
#pragma pop_macro("GEN_DEFINE_ATTRIBUTE_TOKENS")
|
||||
|
||||
// We cannot parse this enum, it has Attribute names as enums
|
||||
CodeEnum enum_code = parse_enum(token_fmt("entries", (StrC)enum_entries, "attribute_toks", (StrC)attribute_entries, stringize(
|
||||
enum Type : u32
|
||||
CodeEnum enum_code;
|
||||
if (use_c_definition)
|
||||
{
|
||||
enum_code = parse_enum(token_fmt("entries", string_to_strc(enum_entries), "attribute_toks", string_to_strc(attribute_entries), stringize(
|
||||
enum TokType
|
||||
{
|
||||
<entries>
|
||||
<attribute_toks>
|
||||
NumTokens
|
||||
Tok_NumTokens,
|
||||
Tok_UnderlyingType = GEN_U32_MAX
|
||||
};
|
||||
)));
|
||||
}
|
||||
else
|
||||
{
|
||||
enum_code = parse_enum(token_fmt("entries", string_to_strc(enum_entries), "attribute_toks", string_to_strc(attribute_entries), stringize(
|
||||
enum TokType : u32
|
||||
{
|
||||
<entries>
|
||||
<attribute_toks>
|
||||
Tok_NumTokens
|
||||
};
|
||||
)));
|
||||
}
|
||||
|
||||
#pragma push_macro("local_persist")
|
||||
#pragma push_macro("do_once_start")
|
||||
@@ -286,12 +438,12 @@ CodeBody gen_etoktype( char const* etok_path, char const* attr_path )
|
||||
#undef local_persist
|
||||
#undef do_once_start
|
||||
#undef do_once_end
|
||||
CodeFn to_str = parse_function(token_fmt("entries", (StrC)to_str_entries, "attribute_toks", (StrC)to_str_attributes, stringize(
|
||||
CodeFn to_str = parse_function(token_fmt("entries", string_to_strc(to_str_entries), "attribute_toks", string_to_strc(to_str_attributes), stringize(
|
||||
inline
|
||||
StrC to_str( Type type )
|
||||
StrC toktype_to_str( TokType type )
|
||||
{
|
||||
local_persist
|
||||
StrC lookup[] {
|
||||
StrC lookup[] = {
|
||||
<entries>
|
||||
<attribute_toks>
|
||||
};
|
||||
@@ -300,16 +452,16 @@ CodeBody gen_etoktype( char const* etok_path, char const* attr_path )
|
||||
}
|
||||
)));
|
||||
|
||||
CodeFn to_type = parse_function( token_fmt( "entries", (StrC)to_str_entries, stringize(
|
||||
CodeFn to_type = parse_function( token_fmt( "entries", string_to_strc(to_str_entries), stringize(
|
||||
inline
|
||||
Type to_type( StrC str )
|
||||
TokType strc_to_toktype( StrC str )
|
||||
{
|
||||
local_persist
|
||||
u32 keymap[ NumTokens ];
|
||||
u32 keymap[ Tok_NumTokens ];
|
||||
do_once_start
|
||||
for ( u32 index = 0; index < NumTokens; index++ )
|
||||
for ( u32 index = 0; index < Tok_NumTokens; index++ )
|
||||
{
|
||||
StrC enum_str = to_str( (Type)index );
|
||||
StrC enum_str = toktype_to_str( (TokType)index );
|
||||
|
||||
// We subtract 1 to remove the null terminator
|
||||
// This is because the tokens lexed are not null terminated.
|
||||
@@ -319,102 +471,59 @@ CodeBody gen_etoktype( char const* etok_path, char const* attr_path )
|
||||
|
||||
u32 hash = crc32( str.Ptr, str.Len );
|
||||
|
||||
for ( u32 index = 0; index < NumTokens; index++ )
|
||||
for ( u32 index = 0; index < Tok_NumTokens; index++ )
|
||||
{
|
||||
if ( keymap[index] == hash )
|
||||
return (Type)index;
|
||||
return (TokType)index;
|
||||
}
|
||||
|
||||
return Invalid;
|
||||
return Tok_Invalid;
|
||||
}
|
||||
)));
|
||||
#pragma pop_macro("local_persist")
|
||||
#pragma pop_macro("do_once_start")
|
||||
#pragma pop_macro("do_once_end")
|
||||
|
||||
CodeNS nspace = def_namespace( name(ETokType), def_namespace_body( args( attribute_entires_def, enum_code, to_str, to_type ) ) );
|
||||
CodeUsing td_toktype = def_using( name(TokType), def_type( name(ETokType::Type) ) );
|
||||
|
||||
return def_global_body( args( nspace, td_toktype ) );
|
||||
CodeBody result = def_body(CT_Global_Body);
|
||||
body_append(result, untyped_str(txt("GEN_NS_PARSER_BEGIN\n\n")));
|
||||
body_append(result, attribute_entires_def);
|
||||
body_append(result, enum_code);
|
||||
if (use_c_definition)
|
||||
{
|
||||
CodeTypedef td_toktype = parse_typedef( code( typedef enum TokType TokType; ));
|
||||
body_append(result, td_toktype);
|
||||
}
|
||||
body_append(result, to_str);
|
||||
body_append(result, to_type);
|
||||
body_append(result, untyped_str(txt("\nGEN_NS_PARSER_END\n\n")));
|
||||
return result;
|
||||
}
|
||||
|
||||
CodeBody gen_ast_inlines()
|
||||
{
|
||||
#pragma push_macro("GEN_NS")
|
||||
#pragma push_macro("rcast")
|
||||
#pragma push_macro("log_failure")
|
||||
#pragma push_macro("CodeInvalid")
|
||||
#undef GEN_NS
|
||||
#undef rcast
|
||||
#undef log_failure
|
||||
#undef CodeInvalid
|
||||
char const* code_impl_tmpl = stringize(
|
||||
\n
|
||||
inline
|
||||
char const* <typename>::debug_str()
|
||||
{
|
||||
if ( ast == nullptr )
|
||||
return "Code::debug_str: AST is null!";
|
||||
|
||||
return rcast(AST*, ast)->debug_str();
|
||||
}
|
||||
inline
|
||||
Code <typename>::duplicate()
|
||||
{
|
||||
if ( ast == nullptr )
|
||||
{
|
||||
log_failure("Code::duplicate: Cannot duplicate code, AST is null!");
|
||||
return Code::Invalid;
|
||||
}
|
||||
|
||||
return { rcast(AST*, ast)->duplicate() };
|
||||
}
|
||||
inline
|
||||
bool <typename>::is_equal( Code other )
|
||||
{
|
||||
if ( ast == nullptr || other.ast == nullptr )
|
||||
{
|
||||
// Just check if they're both null.
|
||||
// log_failure( "Code::is_equal: Cannot compare code, AST is null!" );
|
||||
return ast == nullptr && other.ast == nullptr;
|
||||
}
|
||||
return rcast(AST*, ast)->is_equal( other.ast );
|
||||
}
|
||||
inline
|
||||
bool <typename>::is_valid()
|
||||
{
|
||||
return (AST*) ast != nullptr && rcast( AST*, ast)->Type != CodeT::Invalid;
|
||||
}
|
||||
inline
|
||||
void <typename>::set_global()
|
||||
{
|
||||
if ( ast == nullptr )
|
||||
{
|
||||
log_failure("Code::set_global: Cannot set code as global, AST is null!");
|
||||
return;
|
||||
}
|
||||
|
||||
rcast(AST*, ast)->Parent = Code::Global.ast;
|
||||
}
|
||||
inline
|
||||
<typename>& <typename>::operator =( Code other )
|
||||
{
|
||||
if ( other.ast && other->Parent )
|
||||
if ( other.ast != nullptr && other->Parent != nullptr )
|
||||
{
|
||||
ast = rcast( decltype(ast), other.ast->duplicate() );
|
||||
rcast( AST*, ast)->Parent = nullptr;
|
||||
ast = rcast( decltype(ast), code_duplicate(other).ast);
|
||||
ast->Parent = { nullptr };
|
||||
}
|
||||
|
||||
ast = rcast( decltype( ast ), other.ast );
|
||||
return * this;
|
||||
}
|
||||
inline
|
||||
bool <typename>::operator ==( Code other )
|
||||
{
|
||||
return (AST*) ast == other.ast;
|
||||
}
|
||||
inline
|
||||
bool <typename>::operator !=( Code other )
|
||||
{
|
||||
return (AST*) ast != other.ast;
|
||||
}
|
||||
inline
|
||||
<typename>::operator bool()
|
||||
{
|
||||
return ast != nullptr;
|
||||
@@ -422,11 +531,6 @@ CodeBody gen_ast_inlines()
|
||||
);
|
||||
|
||||
char const* codetype_impl_tmpl = stringize(
|
||||
inline
|
||||
AST* Code<typename>::raw()
|
||||
{
|
||||
return rcast( AST*, ast );
|
||||
}
|
||||
inline
|
||||
Code<typename>::operator Code()
|
||||
{
|
||||
@@ -444,6 +548,8 @@ CodeBody gen_ast_inlines()
|
||||
}
|
||||
\n
|
||||
);
|
||||
#pragma pop_macro("GEN_NS")
|
||||
#pragma pop_macro("CodeInvalid")
|
||||
|
||||
CodeBody impl_code = parse_global_body( token_fmt( "typename", StrC name(Code), code_impl_tmpl ));
|
||||
CodeBody impl_code_body = parse_global_body( token_fmt( "typename", StrC name(CodeBody), code_impl_tmpl ));
|
||||
@@ -469,46 +575,45 @@ CodeBody gen_ast_inlines()
|
||||
CodeBody impl_code_specs = parse_global_body( token_fmt( "typename", StrC name(CodeSpecifiers), code_impl_tmpl ));
|
||||
CodeBody impl_code_struct = parse_global_body( token_fmt( "typename", StrC name(CodeStruct), code_impl_tmpl ));
|
||||
CodeBody impl_code_tmpl = parse_global_body( token_fmt( "typename", StrC name(CodeTemplate), code_impl_tmpl ));
|
||||
CodeBody impl_code_type = parse_global_body( token_fmt( "typename", StrC name(CodeType), code_impl_tmpl ));
|
||||
CodeBody impl_code_type = parse_global_body( token_fmt( "typename", StrC name(CodeTypename), code_impl_tmpl ));
|
||||
CodeBody impl_code_typedef = parse_global_body( token_fmt( "typename", StrC name(CodeTypedef), code_impl_tmpl ));
|
||||
CodeBody impl_code_union = parse_global_body( token_fmt( "typename", StrC name(CodeUnion), code_impl_tmpl ));
|
||||
CodeBody impl_code_using = parse_global_body( token_fmt( "typename", StrC name(CodeUsing), code_impl_tmpl ));
|
||||
CodeBody impl_code_var = parse_global_body( token_fmt( "typename", StrC name(CodeVar), code_impl_tmpl ));
|
||||
|
||||
impl_code_attr. append( parse_global_body( token_fmt( "typename", StrC name(Attributes), codetype_impl_tmpl )));
|
||||
impl_code_cmt. append( parse_global_body( token_fmt( "typename", StrC name(Comment), codetype_impl_tmpl )));
|
||||
impl_code_constr. append( parse_global_body( token_fmt( "typename", StrC name(Constructor), codetype_impl_tmpl )));
|
||||
impl_code_define. append( parse_global_body( token_fmt( "typename", StrC name(Define), codetype_impl_tmpl )));
|
||||
impl_code_destruct.append( parse_global_body( token_fmt( "typename", StrC name(Destructor), codetype_impl_tmpl )));
|
||||
impl_code_enum. append( parse_global_body( token_fmt( "typename", StrC name(Enum), codetype_impl_tmpl )));
|
||||
impl_code_exec. append( parse_global_body( token_fmt( "typename", StrC name(Exec), codetype_impl_tmpl )));
|
||||
impl_code_extern. append( parse_global_body( token_fmt( "typename", StrC name(Extern), codetype_impl_tmpl )));
|
||||
impl_code_include. append( parse_global_body( token_fmt( "typename", StrC name(Include), codetype_impl_tmpl )));
|
||||
impl_code_friend. append( parse_global_body( token_fmt( "typename", StrC name(Friend), codetype_impl_tmpl )));
|
||||
impl_code_fn. append( parse_global_body( token_fmt( "typename", StrC name(Fn), codetype_impl_tmpl )));
|
||||
impl_code_module. append( parse_global_body( token_fmt( "typename", StrC name(Module), codetype_impl_tmpl )));
|
||||
impl_code_ns. append( parse_global_body( token_fmt( "typename", StrC name(NS), codetype_impl_tmpl )));
|
||||
impl_code_op. append( parse_global_body( token_fmt( "typename", StrC name(Operator), codetype_impl_tmpl )));
|
||||
impl_code_opcast. append( parse_global_body( token_fmt( "typename", StrC name(OpCast), codetype_impl_tmpl )));
|
||||
impl_code_pragma . append( parse_global_body( token_fmt( "typename", StrC name(Pragma), codetype_impl_tmpl )));
|
||||
impl_code_precond. append( parse_global_body( token_fmt( "typename", StrC name(PreprocessCond), codetype_impl_tmpl )));
|
||||
impl_code_tmpl. append( parse_global_body( token_fmt( "typename", StrC name(Template), codetype_impl_tmpl )));
|
||||
impl_code_type. append( parse_global_body( token_fmt( "typename", StrC name(Type), codetype_impl_tmpl )));
|
||||
impl_code_typedef. append( parse_global_body( token_fmt( "typename", StrC name(Typedef), codetype_impl_tmpl )));
|
||||
impl_code_union. append( parse_global_body( token_fmt( "typename", StrC name(Union), codetype_impl_tmpl )));
|
||||
impl_code_using. append( parse_global_body( token_fmt( "typename", StrC name(Using), codetype_impl_tmpl )));
|
||||
impl_code_var. append( parse_global_body( token_fmt( "typename", StrC name(Var), codetype_impl_tmpl )));
|
||||
body_append(impl_code_attr, parse_global_body( token_fmt( "typename", StrC name(Attributes), codetype_impl_tmpl )));
|
||||
body_append(impl_code_cmt, parse_global_body( token_fmt( "typename", StrC name(Comment), codetype_impl_tmpl )));
|
||||
body_append(impl_code_constr, parse_global_body( token_fmt( "typename", StrC name(Constructor), codetype_impl_tmpl )));
|
||||
body_append(impl_code_define, parse_global_body( token_fmt( "typename", StrC name(Define), codetype_impl_tmpl )));
|
||||
body_append(impl_code_destruct, parse_global_body( token_fmt( "typename", StrC name(Destructor), codetype_impl_tmpl )));
|
||||
body_append(impl_code_enum, parse_global_body( token_fmt( "typename", StrC name(Enum), codetype_impl_tmpl )));
|
||||
body_append(impl_code_exec, parse_global_body( token_fmt( "typename", StrC name(Exec), codetype_impl_tmpl )));
|
||||
body_append(impl_code_extern, parse_global_body( token_fmt( "typename", StrC name(Extern), codetype_impl_tmpl )));
|
||||
body_append(impl_code_include, parse_global_body( token_fmt( "typename", StrC name(Include), codetype_impl_tmpl )));
|
||||
body_append(impl_code_friend, parse_global_body( token_fmt( "typename", StrC name(Friend), codetype_impl_tmpl )));
|
||||
body_append(impl_code_fn, parse_global_body( token_fmt( "typename", StrC name(Fn), codetype_impl_tmpl )));
|
||||
body_append(impl_code_module, parse_global_body( token_fmt( "typename", StrC name(Module), codetype_impl_tmpl )));
|
||||
body_append(impl_code_ns, parse_global_body( token_fmt( "typename", StrC name(NS), codetype_impl_tmpl )));
|
||||
body_append(impl_code_op, parse_global_body( token_fmt( "typename", StrC name(Operator), codetype_impl_tmpl )));
|
||||
body_append(impl_code_opcast, parse_global_body( token_fmt( "typename", StrC name(OpCast), codetype_impl_tmpl )));
|
||||
body_append(impl_code_pragma, parse_global_body( token_fmt( "typename", StrC name(Pragma), codetype_impl_tmpl )));
|
||||
body_append(impl_code_precond, parse_global_body( token_fmt( "typename", StrC name(PreprocessCond), codetype_impl_tmpl )));
|
||||
body_append(impl_code_tmpl, parse_global_body( token_fmt( "typename", StrC name(Template), codetype_impl_tmpl )));
|
||||
body_append(impl_code_type, parse_global_body( token_fmt( "typename", StrC name(Typename), codetype_impl_tmpl )));
|
||||
body_append(impl_code_typedef, parse_global_body( token_fmt( "typename", StrC name(Typedef), codetype_impl_tmpl )));
|
||||
body_append(impl_code_union, parse_global_body( token_fmt( "typename", StrC name(Union), codetype_impl_tmpl )));
|
||||
body_append(impl_code_using, parse_global_body( token_fmt( "typename", StrC name(Using), codetype_impl_tmpl )));
|
||||
body_append(impl_code_var, parse_global_body( token_fmt( "typename", StrC name(Var), codetype_impl_tmpl )));
|
||||
|
||||
#pragma push_macro("forceinline")
|
||||
#undef forceinline
|
||||
char const* cast_tmpl = stringize(
|
||||
inline AST::operator Code<typename>()
|
||||
{
|
||||
return { rcast( AST_<typename>*, this ) };
|
||||
}
|
||||
inline Code::operator Code<typename>() const
|
||||
forceinline Code::operator Code<typename>() const
|
||||
{
|
||||
return { (AST_<typename>*) ast };
|
||||
}
|
||||
);
|
||||
#pragma pop_macro("forceinline")
|
||||
|
||||
CodeBody impl_cast_body = parse_global_body( token_fmt( "typename", StrC name(Body), cast_tmpl ));
|
||||
CodeBody impl_cast_attribute = parse_global_body( token_fmt( "typename", StrC name(Attributes), cast_tmpl ));
|
||||
@@ -533,7 +638,7 @@ CodeBody gen_ast_inlines()
|
||||
CodeBody impl_cast_specs = parse_global_body( token_fmt( "typename", StrC name(Specifiers), cast_tmpl ));
|
||||
CodeBody impl_cast_struct = parse_global_body( token_fmt( "typename", StrC name(Struct), cast_tmpl ));
|
||||
CodeBody impl_cast_tmpl = parse_global_body( token_fmt( "typename", StrC name(Template), cast_tmpl ));
|
||||
CodeBody impl_cast_type = parse_global_body( token_fmt( "typename", StrC name(Type), cast_tmpl ));
|
||||
CodeBody impl_cast_type = parse_global_body( token_fmt( "typename", StrC name(Typename), cast_tmpl ));
|
||||
CodeBody impl_cast_typedef = parse_global_body( token_fmt( "typename", StrC name(Typedef), cast_tmpl ));
|
||||
CodeBody impl_cast_union = parse_global_body( token_fmt( "typename", StrC name(Union), cast_tmpl ));
|
||||
CodeBody impl_cast_using = parse_global_body( token_fmt( "typename", StrC name(Using), cast_tmpl ));
|
||||
@@ -575,6 +680,7 @@ CodeBody gen_ast_inlines()
|
||||
def_pragma( txt("endregion generated code inline implementation")),
|
||||
fmt_newline,
|
||||
def_pragma( txt("region generated AST/Code cast implementation")),
|
||||
untyped_str(txt("GEN_OPTIMIZE_MAPPINGS_BEGIN\n")),
|
||||
fmt_newline,
|
||||
impl_cast_body,
|
||||
impl_cast_attribute,
|
||||
@@ -605,6 +711,7 @@ CodeBody gen_ast_inlines()
|
||||
impl_cast_using,
|
||||
impl_cast_var,
|
||||
fmt_newline,
|
||||
untyped_str(txt("GEN_OPITMIZE_MAPPINGS_END\n")),
|
||||
def_pragma( txt("endregion generated AST/Code cast implementation")),
|
||||
fmt_newline
|
||||
));
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "gen.hpp"
|
||||
|
||||
GEN_NS_BEGIN
|
||||
#include "dependencies/parsing.hpp"
|
||||
GEN_NS_END
|
||||
|
||||
using namespace gen;
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
|
||||
#undef array_init
|
||||
#undef array_init_reserve
|
||||
#undef array_append_array
|
||||
#undef array_append
|
||||
#undef array_append_items
|
||||
#undef array_append_at
|
||||
#undef array_append_items_at
|
||||
#undef array_back
|
||||
#undef array_clear
|
||||
#undef array_fill
|
||||
#undef array_free
|
||||
#undef arary_grow
|
||||
#undef array_num
|
||||
#undef arary_pop
|
||||
#undef arary_remove_at
|
||||
#undef arary_reserve
|
||||
#undef arary_resize
|
||||
#undef arary_set_capacity
|
||||
#undef arary_get_header
|
||||
|
||||
#undef hashtable_init
|
||||
#undef hashtable_init_reserve
|
||||
#undef hashtable_clear
|
||||
#undef hashtable_destroy
|
||||
#undef hashtable_get
|
||||
#undef hashtable_grow
|
||||
#undef hashtable_rehash
|
||||
#undef hashtable_rehash_fast
|
||||
#undef hashtable_remove
|
||||
#undef hashtable_remove_entry
|
||||
#undef hashtable_set
|
||||
#undef hashtable_slot
|
||||
#undef hashtable_map
|
||||
#undef hashtable_map_mut
|
||||
|
||||
//#undef hashtable_add_entry
|
||||
//#undef hashtable_find
|
||||
//#undef hashtable_full
|
||||
@@ -0,0 +1,39 @@
|
||||
|
||||
#define array_init(type, allocator) array_init <type> (allocator )
|
||||
#define array_init_reserve(type, allocator, cap) array_init_reserve <type> (allocator, cap)
|
||||
#define array_append_array(array, other) array_append_array < get_array_underlying_type(array) > (& array, other )
|
||||
#define array_append(array, value) array_append < get_array_underlying_type(array) > (& array, value )
|
||||
#define array_append_items(array, items, item_num) array_append_items < get_array_underlying_type(array) > (& array, items, item_num )
|
||||
#define array_append_at(array, item, idx ) array_append_at < get_array_underlying_type(array) > (& array, item, idx )
|
||||
#define array_append_at_items(array, items, item_num, idx) array_append_at_items< get_array_underlying_type(array) > (& items, item_num, idx )
|
||||
#define array_back(array) array_back < get_array_underlying_type(array) > (array )
|
||||
#define array_clear(array) array_clear < get_array_underlying_type(array) > (array )
|
||||
#define array_fill(array, begin, end, value) array_fill < get_array_underlying_type(array) > (array, begin, end, value )
|
||||
#define array_free(array) array_free < get_array_underlying_type(array) > (& array )
|
||||
#define arary_grow(array, min_capacity) arary_grow < get_array_underlying_type(array) > (& array, min_capacity)
|
||||
#define array_num(array) array_num < get_array_underlying_type(array) > (array )
|
||||
#define arary_pop(array) arary_pop < get_array_underlying_type(array) > (array )
|
||||
#define arary_remove_at(array, idx) arary_remove_at < get_array_underlying_type(array) > (idx)
|
||||
#define arary_reserve(array, new_capacity) arary_reserve < get_array_underlying_type(array) > (& array, new_capacity )
|
||||
#define arary_resize(array, num) arary_resize < get_array_underlying_type(array) > (& array, num)
|
||||
#define arary_set_capacity(new_capacity) arary_set_capacity < get_array_underlying_type(array) > (& array, new_capacity )
|
||||
#define arary_get_header(array) arary_get_header < get_array_underlying_type(array) > (array )
|
||||
|
||||
#define hashtable_init(type, allocator) hashtable_init <type >(allocator)
|
||||
#define hashtable_init_reserve(type, allocator, num) hashtable_init_reserve<type >(allocator, num)
|
||||
#define hashtable_clear(table) hashtable_clear < get_hashtable_underlying_type(table) >(table)
|
||||
#define hashtable_destroy(table) hashtable_destroy < get_hashtable_underlying_type(table) >(& table)
|
||||
#define hashtable_get(table, key) hashtable_get < get_hashtable_underlying_type(table) >(table, key)
|
||||
#define hashtable_grow(table) hashtable_grow < get_hashtable_underlying_type(table) >(& table)
|
||||
#define hashtable_rehash(table, new_num) hashtable_rehash < get_hashtable_underlying_type(table) >(& table, new_num)
|
||||
#define hashtable_rehash_fast(table) hashtable_rehash_fast < get_hashtable_underlying_type(table) >(table)
|
||||
#define hashtable_remove(table, key) hashtable_remove < get_hashtable_underlying_type(table) >(table, key)
|
||||
#define hashtable_remove_entry(table, idx) hashtable_remove_entry< get_hashtable_underlying_type(table) >(table, idx)
|
||||
#define hashtable_set(table, key, value) hashtable_set < get_hashtable_underlying_type(table) >(& table, key, value)
|
||||
#define hashtable_slot(table, key) hashtable_slot < get_hashtable_underlying_type(table) >(table, key)
|
||||
#define hashtable_map(table, map_proc) hashtable_map < get_hashtable_underlying_type(table) >(table, map_proc)
|
||||
#define hashtable_map_mut(table, map_proc) hashtable_map_mut < get_hashtable_underlying_type(table) >(table, map_proc)
|
||||
|
||||
//#define hashtable_add_entry(table, key) hashtable_add_entry < get_hashtable_underlying_type(table) >(& table, key)
|
||||
//#define hashtable_find(table, key) hashtable_find < get_hashtable_underlying_type(table) >(table, key)
|
||||
//#define hashtable_full(table) hashtable_full < get_hashtable_underlying_type(table) >(table)
|
||||
@@ -7,6 +7,9 @@
|
||||
# pragma clang diagnostic ignored "-Wunknown-pragmas"
|
||||
# pragma clang diagnostic ignored "-Wvarargs"
|
||||
# pragma clang diagnostic ignored "-Wunused-function"
|
||||
# pragma clang diagnostic ignored "-Wbraced-scalar-init"
|
||||
# pragma clang diagnostic ignored "-W#pragma-messages"
|
||||
# pragma clang diagnostic ignored "-Wstatic-in-inline"
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
|
||||
+76
-12
@@ -2,15 +2,12 @@
|
||||
# It will most likely need a partial rewrite to segment the build process into separate script invocations based on the OS.
|
||||
# That or just rewrite it in an sh script and call it a day.
|
||||
|
||||
$target_arch = Join-Path $PSScriptRoot 'helpers/target_arch.psm1'
|
||||
$devshell = Join-Path $PSScriptRoot 'helpers/devshell.ps1'
|
||||
$format_cpp = Join-Path $PSScriptRoot 'helpers/format_cpp.psm1'
|
||||
$refactor_unreal = Join-Path $PSScriptRoot 'refactor_unreal.ps1'
|
||||
$incremental_checks = Join-Path $PSScriptRoot 'helpers/incremental_checks.ps1'
|
||||
$vendor_toolchain = Join-Path $PSScriptRoot 'helpers/vendor_toolchain.ps1'
|
||||
|
||||
Import-Module $target_arch
|
||||
|
||||
function Get-ScriptRepoRoot {
|
||||
$currentPath = $PSScriptRoot
|
||||
while ($currentPath -ne $null -and $currentPath -ne "")
|
||||
@@ -33,7 +30,7 @@ function Get-ScriptRepoRoot {
|
||||
}
|
||||
$path_root = Get-ScriptRepoRoot
|
||||
|
||||
Import-Module $target_arch
|
||||
# Import-Module $target_arch
|
||||
Import-Module $format_cpp
|
||||
|
||||
Push-Location $path_root
|
||||
@@ -44,6 +41,7 @@ Push-Location $path_root
|
||||
$verbose = $false
|
||||
[bool] $bootstrap = $false
|
||||
[bool] $singleheader = $false
|
||||
[bool] $c_library = $false
|
||||
[bool] $unreal = $false
|
||||
[bool] $test = $false
|
||||
|
||||
@@ -59,6 +57,7 @@ if ( $args ) { $args | ForEach-Object {
|
||||
"debug" { $release = $false }
|
||||
"bootstrap" { $bootstrap = $true }
|
||||
"singleheader" { $singleheader = $true }
|
||||
"c_library" { $c_library = $true }
|
||||
"unreal" { $unreal = $true }
|
||||
"test" { $test = $true }
|
||||
}
|
||||
@@ -88,11 +87,10 @@ else {
|
||||
$optimize = $true
|
||||
}
|
||||
|
||||
if ( $bootstrap -eq $false -and $singleheader -eq $false -and $unreal -eq $false -and $test -eq $false ) {
|
||||
if ( $bootstrap -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"
|
||||
}
|
||||
|
||||
|
||||
. $vendor_toolchain
|
||||
. $incremental_checks
|
||||
|
||||
@@ -103,8 +101,9 @@ write-host "Build Type: $(if ($release) {"Release"} else {"Debug"} )"
|
||||
$path_build = Join-Path $path_root build
|
||||
$path_project = Join-Path $path_root project
|
||||
$path_scripts = Join-Path $path_root scripts
|
||||
$path_singleheader = Join-Path $path_root singleheader
|
||||
$path_unreal = Join-Path $path_root unreal_engine
|
||||
$path_c_library = join-Path $path_root gen_c_library
|
||||
$path_singleheader = Join-Path $path_root gen_singleheader
|
||||
$path_unreal = Join-Path $path_root gen_unreal_engine
|
||||
$path_test = Join-Path $path_root test
|
||||
|
||||
if ( $bootstrap )
|
||||
@@ -134,7 +133,7 @@ if ( $bootstrap )
|
||||
$unit = join-path $path_project "bootstrap.cpp"
|
||||
$executable = join-path $path_build "bootstrap.exe"
|
||||
|
||||
build-simple $path_build $includes $compiler_args $linker_args $unit $executable
|
||||
$result = build-simple $path_build $includes $compiler_args $linker_args $unit $executable
|
||||
|
||||
Push-Location $path_project
|
||||
if ( Test-Path( $executable ) ) {
|
||||
@@ -172,7 +171,7 @@ if ( $singleheader )
|
||||
$flag_link_win_subsystem_console
|
||||
)
|
||||
|
||||
build-simple $path_build $includes $compiler_args $linker_args $unit $executable
|
||||
$result = build-simple $path_build $includes $compiler_args $linker_args $unit $executable
|
||||
|
||||
Push-Location $path_singleheader
|
||||
if ( Test-Path( $executable ) ) {
|
||||
@@ -187,6 +186,71 @@ if ( $singleheader )
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
if ( $c_library )
|
||||
{
|
||||
$path_build = join-path $path_c_library build
|
||||
$path_gen = join-path $path_c_library 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
|
||||
}
|
||||
|
||||
$includes = @( $path_project )
|
||||
$unit = join-path $path_c_library "c_library.cpp"
|
||||
$executable = join-path $path_build "c_library.exe"
|
||||
|
||||
$compiler_args = @()
|
||||
$compiler_args += ( $flag_define + 'GEN_TIME' )
|
||||
|
||||
$linker_args = @(
|
||||
$flag_link_win_subsystem_console
|
||||
)
|
||||
|
||||
$result = build-simple $path_build $includes $compiler_args $linker_args $unit $executable
|
||||
|
||||
Push-Location $path_c_library
|
||||
if ( Test-Path( $executable ) ) {
|
||||
write-host "`nRunning c_library generator"
|
||||
$time_taken = Measure-Command { & $executable
|
||||
| ForEach-Object {
|
||||
write-host `t $_ -ForegroundColor Green
|
||||
}
|
||||
}
|
||||
write-host "`nc_library generator completed in $($time_taken.TotalMilliseconds) ms"
|
||||
}
|
||||
Pop-Location
|
||||
|
||||
$unit = join-path $path_c_library "gen.c"
|
||||
$executable = join-path $path_build "gen_c_library_test.exe"
|
||||
|
||||
if ($vendor -eq "clang") {
|
||||
$compiler_args += '-x'
|
||||
$compiler_args += 'c'
|
||||
$compiler_args += '-std=c11'
|
||||
} elseif ($vendor -eq "msvc") {
|
||||
$compiler_args += "/TC" # Compile as C
|
||||
$compiler_args += "/Zc:__cplusplus" # Fix __cplusplus macro
|
||||
$compiler_args += "/std:c11"
|
||||
}
|
||||
|
||||
$result = build-simple $path_build $includes $compiler_args $linker_args $unit $executable
|
||||
|
||||
Push-Location $path_c_library
|
||||
if ( Test-Path( $executable ) ) {
|
||||
write-host "`nRunning c_library test"
|
||||
$time_taken = Measure-Command { & $executable
|
||||
| ForEach-Object {
|
||||
write-host `t $_ -ForegroundColor Green
|
||||
}
|
||||
}
|
||||
write-host "`nc_library generator completed in $($time_taken.TotalMilliseconds) ms"
|
||||
}
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
if ( $unreal )
|
||||
{
|
||||
$path_build = join-path $path_unreal build
|
||||
@@ -210,7 +274,7 @@ if ( $unreal )
|
||||
$flag_link_win_subsystem_console
|
||||
)
|
||||
|
||||
build-simple $path_build $includes $compiler_args $linker_args $unit $executable
|
||||
$result = build-simple $path_build $includes $compiler_args $linker_args $unit $executable
|
||||
|
||||
Push-Location $path_unreal
|
||||
if ( Test-Path( $executable ) ) {
|
||||
@@ -272,7 +336,7 @@ if ( $test )
|
||||
$flag_link_win_subsystem_console
|
||||
)
|
||||
|
||||
build-simple $path_build $includes $compiler_args $linker_args $unit $executable
|
||||
$result = build-simple $path_build $includes $compiler_args $linker_args $unit $executable
|
||||
|
||||
Push-Location $path_test
|
||||
Write-Host $path_test
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
__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
|
||||
// namespace : Prefix search and replace (c-namspaces).
|
||||
// regex : Unavailable in __VERSION 1.
|
||||
|
||||
// Precedence (highest to lowest):
|
||||
// word, namespace, regex
|
||||
|
||||
// Gen Macro namespace
|
||||
// namespace GEN_, new_namespace_
|
||||
|
||||
// TODO(Ed): This will be large as nearly all symbols will need to optionally support getting prefixed with gen_ or something else the user wants.
|
||||
@@ -253,7 +253,7 @@
|
||||
|
||||
// word log_failure, new_name
|
||||
|
||||
// word NoCode, new_name
|
||||
// word NullCode, new_name
|
||||
// word CodeInvalid, new_name
|
||||
|
||||
// ------------ gencpp common
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
# This is meant to be used with build.ps1, and is not a standalone script.
|
||||
$target_arch = Join-Path $PSScriptRoot 'target_arch.psm1'
|
||||
|
||||
import-module $target_arch
|
||||
|
||||
if ($IsWindows) {
|
||||
# This HandmadeHero implementation is only designed for 64-bit systems
|
||||
@@ -188,7 +191,7 @@ if ( $vendor -match "clang" )
|
||||
# $compiler_args += $flag_time_trace
|
||||
}
|
||||
if ( $optimize ) {
|
||||
$compiler_args += $flag_optimize_fast
|
||||
$compiler_args += $flag_optimize_size
|
||||
}
|
||||
else {
|
||||
$compiler_args += $flag_no_optimization
|
||||
@@ -268,7 +271,7 @@ if ( $vendor -match "clang" )
|
||||
# $compiler_args += $flag_time_trace
|
||||
}
|
||||
if ( $optimize ) {
|
||||
$compiler_args += $flag_optimize_fast
|
||||
$compiler_args += $flag_optimize_size
|
||||
}
|
||||
else {
|
||||
$compiler_args += $flag_no_optimization
|
||||
@@ -348,7 +351,9 @@ if ( $vendor -match "msvc" )
|
||||
$flag_optimize_fast = '/O2'
|
||||
$flag_optimize_size = '/O1'
|
||||
$flag_optimize_intrinsics = '/Oi'
|
||||
$flag_optimized_debug_forceinline = '/d2Obforceinline'
|
||||
$flag_optimized_debug = '/Zo'
|
||||
$flag_
|
||||
$flag_out_name = '/OUT:'
|
||||
$flag_path_interm = '/Fo'
|
||||
$flag_path_debug = '/Fd'
|
||||
@@ -388,7 +393,7 @@ if ( $vendor -match "msvc" )
|
||||
}
|
||||
|
||||
if ( $optimize ) {
|
||||
$compiler_args += $flag_optimize_fast
|
||||
$compiler_args += $flag_optimize_size
|
||||
}
|
||||
else {
|
||||
$compiler_args += $flag_no_optimization
|
||||
@@ -403,6 +408,7 @@ if ( $vendor -match "msvc" )
|
||||
|
||||
if ( $optimize ) {
|
||||
$compiler_args += $flag_optimized_debug
|
||||
$compiler_args += $flag_optimized_debug_forceinline
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -474,7 +480,7 @@ if ( $vendor -match "msvc" )
|
||||
}
|
||||
|
||||
if ( $optimize ) {
|
||||
$compiler_args += $flag_optimize_fast
|
||||
$compiler_args += $flag_optimize_size
|
||||
}
|
||||
else {
|
||||
$compiler_args += $flag_no_optimization
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
gencpp: An attempt at "simple" staged metaprogramming for c/c++.
|
||||
|
||||
See Readme.md for more information from the project repository.
|
||||
|
||||
Public Address:
|
||||
https://github.com/Ed94/gencpp
|
||||
|
||||
This is a single header variant of the library.
|
||||
Define GEN_IMPLEMENTATION before including this file in a single compilation unit.
|
||||
*/
|
||||
#if ! defined(GEN_DONT_ENFORCE_GEN_TIME_GUARD) && ! defined(GEN_TIME)
|
||||
# error Gen.hpp : GEN_TIME not defined
|
||||
#endif
|
||||
|
||||
#ifdef GEN_DONT_USE_NAMESPACE
|
||||
# define GEN_NS_BEGIN
|
||||
# define GEN_NS_END
|
||||
#else
|
||||
# define GEN_NS_BEGIN namespace gen {
|
||||
# define GEN_NS_END }
|
||||
#endif
|
||||
|
||||
@@ -50,7 +50,7 @@ u32 gen_sanity_upfront()
|
||||
|
||||
// Enum
|
||||
{
|
||||
CodeEnum fwd = def_enum( name(ETestEnum), NoCode, t_u8 );
|
||||
CodeEnum fwd = def_enum( name(ETestEnum), NullCode, t_u8 );
|
||||
CodeEnum def;
|
||||
{
|
||||
Code body = untyped_str( code(
|
||||
@@ -62,7 +62,7 @@ u32 gen_sanity_upfront()
|
||||
def = def_enum( name(ETestEnum), body, t_u8 );
|
||||
}
|
||||
|
||||
CodeEnum fwd_enum_class = def_enum( name(ETestEnumClass), NoCode, t_u8, EnumClass );
|
||||
CodeEnum fwd_enum_class = def_enum( name(ETestEnumClass), NullCode, t_u8, EnumClass );
|
||||
|
||||
gen_sanity_file.print(fwd);
|
||||
gen_sanity_file.print(def);
|
||||
|
||||
Reference in New Issue
Block a user