14 Commits

Author SHA1 Message Date
Ed_
3133977b0f Update Readme.md
UE vod
2024-12-16 17:49:09 -05:00
Ed_
e4088185af mp4 readme test 2 2024-12-16 17:38:16 -05:00
Ed_
c55151886f progress in parser_algo docs, testing mp4 in readme 2024-12-16 17:34:17 -05:00
Ed_
6689235691 minor updates for better unused code cleanup in the c_library 2024-12-16 17:18:52 -05:00
Ed_
6533a3be29 Name correction for parser switch case macros 2024-12-16 15:05:23 -05:00
Ed_
adbcb2a83b Progress on parser documentation 2024-12-16 14:57:01 -05:00
Ed_
15847f10b9 ast_types.md: Formatting, Updates to AST_Design.md & AST_Types.md 2024-12-16 12:26:17 -05:00
Ed_
8952cf5f1b docs/Readme.md updated 2024-12-16 12:01:51 -05:00
Ed_
2bdd49fd19 Progress & proofing of docs 2024-12-16 11:36:09 -05:00
Ed_
0f95c916dd update license again... 2024-12-16 10:43:28 -05:00
Ed_
527fb3b132 Progress on docs, adjustments 2024-12-16 10:36:55 -05:00
Ed_
abffa74ad8 Update license with special thanks 2024-12-16 10:36:30 -05:00
Ed_
772d0de5c1 proofing 2024-12-16 00:58:25 -05:00
Ed_
cb50f93af5 Updates to gen_c_library docs 2024-12-16 00:47:46 -05:00
33 changed files with 1671 additions and 836 deletions

16
LICENSE
View File

@ -26,3 +26,19 @@ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Source URL: https://github.com/Ed94/gencpp
Acknowledgements
* The dependencies for gencpp source are derived from the zpl library: https://github.com/zpl-c/zpl
Special thanks to:
* The Handmade Community.
* Casey Muratori, Ginger Bill (Bill Hall), Mr. 4th (Allen Webster), Ryan Fluery: Influnced conceptually how to handle staged metaprograming.
* Jonathan Blow: Jai's metaprogramming influenced the design of this library.
* My friends for putting up with discord spam on this library.

View File

@ -147,3 +147,13 @@ struct ArrayHeader
## Building
See the [scripts directory](scripts/).
## Gallery
### Listing definitions in the Cuik Compiler
### Unreal: Generating a UAttributeSet from a UDataTable
https://github.com/user-attachments/assets/2a07b743-825d-4f9f-beaf-3559e8748a4d

View File

@ -8,7 +8,13 @@
The library is fragmented into a series of headers and source files meant to be scanned in and then generated to a standard target format, or a user's desires.
Standard formats:
If using the library's provided build scripts:
```ps1
.\build.ps1 <compiler> <debug or omit> base
```
## Content Overview
* **base**: Files are in granular pieces separated into four directories:
* **dependencies**: Originally from the c-zpl library and modified thereafter.
@ -27,7 +33,7 @@ Standard formats:
* **gen_segemetned**: Dependencies go into gen.dep.{hpp/cpp} and components into gen.{hpp/cpp}
* **gen_singleheader**: Everything into a single file: gen.hpp
* **gen_unreal_engine**: Like gen_segemented but the library is modified slightly to compile as a thirdparty library within an Unreal Engine plugin or module.
* **gen_c_library**: The library is heavily modifed into C11 compliant code. A segemented and single-header set of variants are generatd.
* **gen_c_library**: The library is heavily modifed into C11 compliant code. A segemented and single-header set of variants are generated.
Code not making up the core library is located in `auxiliary/<auxiliary_name>.<hpp/cpp>`. These are optional extensions or tools for the library.
@ -117,15 +123,15 @@ The vast majority of macros should be single-line subsitutions that either add:
There are ***five*** header files which are automatically generated using [base_codegen.hpp](./helpers/base_codegen.hpp) by [base.cpp](./base.cpp). They are all located in [components/gen](./components/gen/).
* [`ecodetypes.hpp`](./components/gen/ecode.hpp): `CodeType` enum definition and related implementaiton. Generation is based off of [`ECodeType.csv](./enums/ECodeTypes.csv).
* [`especifier.hpp`](./components/gen/especifier.hpp): `Specifier` enum definition, etc. Generated using [`ESpecifier.csv`](./enums/ESpecifier.csv).
* [`eoperator.hpp`](./components/gen/eoperator.hpp): `Operator` enum definition, etc. Generated using [`EOperator.hpp`](./enums/EOperator.csv).
* [`etoktype.cpp`](./components/gen/etoktype.cpp): `TokType` enum defininition, etc. Used by the lexer and parser backend. Uses two csvs:
* [`ETokType.csv`](./enums/ETokType.csv): Provides the enum entries and their strinng ids.
* [`AttributeTokens.csv`](./enums/AttributeTokens.csv): Provides tokens entries that should be considered as attributes by the lexer and parser. Sspecfiically macro attributes such as those use for exporting symbols.
* [`ast_inlines.hpp`](./components/gen/ast_inlines.hpp): Member trivial `operator` definitions for C++ code types. Does not use a csv.
* [ecodetypes.hpp](./components/gen/ecode.hpp): `CodeType` enum definition and related implementaiton. Generation is based off of [ECodeType.csv](./enums/ECodeTypes.csv).
* [especifier.hpp](./components/gen/especifier.hpp): `Specifier` enum definition, etc. Generated using [ESpecifier.csv](./enums/ESpecifier.csv).
* [eoperator.hpp](./components/gen/eoperator.hpp): `Operator` enum definition, etc. Generated using [EOperator.hpp](./enums/EOperator.csv).
* [etoktype.cpp](./components/gen/etoktype.cpp): `TokType` enum defininition, etc. Used by the lexer and parser backend. Uses two csvs:
* [ETokType.csv](./enums/ETokType.csv): Provides the enum entries and their strinng ids.
* [AttributeTokens.csv](./enums/AttributeTokens.csv): Provides tokens entries that should be considered as attributes by the lexer and parser. Sspecfiically macro attributes such as those use for exporting symbols.
* [ast_inlines.hpp](./components/gen/ast_inlines.hpp): Member trivial `operator` definitions for C++ code types. Does not use a csv.
[`misc.hpp`](./helpers/misc.hpp): Has shared functions used by the library generation meta-programs throughout this codebase.
[misc.hpp](./helpers/misc.hpp): Has shared functions used by the library generation meta-programs throughout this codebase.
If using the library's provided build scripts:
@ -154,9 +160,53 @@ Names or Content fields are interned strings and thus showed be cached using `ca
`def_operator` is the most sophisticated upfront constructor as it has multiple permutations of definitions that could be created that are not trivial to determine if valid.
The parser is documented under [`docs/Parsing.md`](../docs/Parsing.md) and [`docs/Parser_Algo.md`](../docs/Parser_Algo.md).
The parser is documented under [`docs/Parsing.md`](../docs/Parsing.md) and [`docs/Parser_Algo.md`](../docs/Parser_Algo.md). Read that and the entire library if you want to extend it.
### Attributes
To add additional macro attributes, all that has to be done is modifying [`AttributeTokens.csv`](./enums/AttributeTokens.csv).
### Specifiers
To add additional macro specifiers, the following needs to be done:
1. Adjust [especifier.hpp](./components/gen/especifier.hpp)
2. Adjust [etoktype.cpp](./components/gen/etoktype.cpp)
3. Adjust [parser_case_macros.cpp](./components/parser_case_macros.cpp)
If the specifier is a new trailing specifier on function definitions:
Head into [base_codegen.hpp](./helpers/base_codegen.hpp): `gen_especifier`. There will be an `is_trailing` function that needs to be adjusted with an additional case for the user's new trailing specifier.
### Code Types
These require the following to be handled to the equivalent extent as the other types:
1. Adjust [ECodeTypes.csv](./enums/ECodeTypes.csv) with the new types
2. Define a new `AST_<Name>` and `Code<Name>`. See
* [ast.hpp](./components/ast.hpp): Initial forwards and user defined conversion for Code.
* [ast_types.hpp](./components/ast_types.hpp): Define the `AST_<Name>` struct.
* [code_types.hpp](./components/code_types.hpp): Defne the `CodeType` struct. If its needs an iterator see: `struct CodeBody` & `struct CodeParams`.
3. [ast_case_macros.cpp](./components/ast_case_macros.cpp): Review cases here if the new code type needs to be considered.
4. [ast.cpp](./components/ast.cpp): Need to review
* `code_debug_str`
* `code_is_equal`
* `code_to_strbuilder_ptr`
* `code_validate_body`
5. [code_serialization.cpp](./components/code_serialization.cpp): Define serialization here.
6. [inlines.hpp](./components/inlines.hpp): Any inline definitions for the `struct Code<Name>` are defined here.
7. [interface.cpp](./components/interface.hpp): Define the `Code<Name>` upfront and parsing interface.
8. [interface.upfront.cpp](./components/interface.upfront.cpp): Define the upfront constructor implementation.
9. [interface.parsing.cpp](./components/interface.parsing.cpp): Define the parsing interface implementation.
10. [lexer.cpp](./components/lexer.cpp): Adjust the lexer as needed.
11. [parser.cpp](./components/parser.cpp): Adjust the parser as needed.
## A note on compilation and runtime generation speed
The library is designed to be fast to compile and generate code at runtime as fast as resonable possible on a debug build.
The library is designed to be fast to compile and generate code at runtime as fast as possible on a debug build.
Its recommended that your metaprogam be compiled using a single translation unit (unity build).
## Whats with the expression / executions support #ifd and enums?
The library is a *work in progress* and those are unfinished hypotheticals for adding the ability to manage or parse the AST of expresions or execution scope code.
They are entirely untested and not meant to be used yet, futher there is no parsing support or an upfront interface for what CodeTypes are defined so far.

View File

@ -1,6 +1,5 @@
#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"

View File

@ -43,7 +43,7 @@ struct AST_Pragma;
struct AST_PreprocessCond;
struct AST_Specifiers;
#if GEN_EXECUTION_EXPRESSION_SUPPORT
#ifdef GEN_EXECUTION_EXPRESSION_SUPPORT
struct AST_Expr;
struct AST_Expr_Assign;
struct AST_Expr_Alignof;
@ -140,7 +140,7 @@ struct CodePragma;
struct CodeSpecifiers;
#endif
#if GEN_EXECUTION_EXPRESSION_SUPPORT
#ifdef GEN_EXECUTION_EXPRESSION_SUPPORT
#if GEN_COMPILER_C
typedef AST_Expr* CodeExpr;

View File

@ -29,16 +29,16 @@
struct AST_Body
{
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
};
StrCached Name;
Code Front;
Code Back;
Token* Tok;
Code Parent;
CodeType Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) ];
s32 NumEntries;
StrCached Name;
Code Front;
Code Back;
Token* Tok;
Code Parent;
CodeType Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) ];
s32 NumEntries;
};
static_assert( sizeof(AST_Body) == sizeof(AST), "ERROR: AST_Body is not the same size as AST");
@ -47,7 +47,7 @@ struct AST_Attributes
{
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
StrCached Content;
StrCached Content;
};
StrCached Name;
Code Prev;
@ -65,7 +65,7 @@ struct AST_BaseClass
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
};
StrCached Name;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
@ -82,7 +82,7 @@ struct AST_Comment
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
StrCached Content;
};
StrCached Name;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
@ -100,14 +100,14 @@ struct AST_Class
{
CodeComment InlineCmt; // Only supported by forward declarations
CodeAttributes Attributes;
char _PAD_SPECS_ [ sizeof(AST*) ];
char _PAD_SPECS_ [ sizeof(AST*) ];
CodeTypename ParentType;
char _PAD_PARAMS_[ sizeof(AST*) ];
char _PAD_PARAMS_[ sizeof(AST*) ];
CodeBody Body;
char _PAD_PROPERTIES_2_[ sizeof(AST*) ];
char _PAD_PROPERTIES_2_[ sizeof(AST*) ];
};
};
StrCached Name;
StrCached Name;
CodeTypename Prev;
CodeTypename Next;
Token* Tok;
@ -130,10 +130,10 @@ struct AST_Constructor
Code InitializerList;
CodeParams Params;
Code Body;
char _PAD_PROPERTIES_2_ [ sizeof(AST*) * 2 ];
char _PAD_PROPERTIES_2_ [ sizeof(AST*) * 2 ];
};
};
StrCached Name;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
@ -155,13 +155,13 @@ struct AST_Define
char _PAD_PROPERTIES_2_ [ sizeof(AST*) * 1 ];
};
};
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ];
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ];
};
static_assert( sizeof(AST_Define) == sizeof(AST), "ERROR: AST_Define is not the same size as AST");
@ -176,7 +176,7 @@ struct AST_DefineParams
Token* Tok;
Code Parent;
CodeType Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) ];
char _PAD_UNUSED_[ sizeof(ModuleFlag) ];
s32 NumEntries;
};
static_assert( sizeof(AST_DefineParams) == sizeof(AST), "ERROR: AST_DefineParams is not the same size as AST");
@ -192,10 +192,10 @@ struct AST_Destructor
CodeSpecifiers Specs;
char _PAD_PROPERTIES_2_ [ sizeof(AST*) * 2 ];
Code Body;
char _PAD_PROPERTIES_3_ [ sizeof(AST*) ];
char _PAD_PROPERTIES_3_ [ sizeof(AST*) ];
};
};
StrCached Name;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
@ -217,10 +217,10 @@ struct AST_Enum
CodeTypename UnderlyingType;
Code UnderlyingTypeMacro;
CodeBody Body;
char _PAD_PROPERTIES_2_[ sizeof(AST*) ];
char _PAD_PROPERTIES_2_[ sizeof(AST*) ];
};
};
StrCached Name;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
@ -237,7 +237,7 @@ struct AST_Exec
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
StrCached Content;
};
StrCached Name;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
@ -247,7 +247,7 @@ struct AST_Exec
};
static_assert( sizeof(AST_Exec) == sizeof(AST), "ERROR: AST_Exec is not the same size as AST");
#if GEN_EXECUTION_EXPRESSION_SUPPORT
#ifdef GEN_EXECUTION_EXPRESSION_SUPPORT
struct AST_Expr
{
union {
@ -515,13 +515,13 @@ struct AST_Extern
char _PAD_PROPERTIES_2_[ sizeof(AST*) ];
};
};
StrCached Name;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ];
char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ];
};
static_assert( sizeof(AST_Extern) == sizeof(AST), "ERROR: AST_Extern is not the same size as AST");
@ -531,13 +531,13 @@ struct AST_Include
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
StrCached Content;
};
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ];
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ];
};
static_assert( sizeof(AST_Include) == sizeof(AST), "ERROR: AST_Include is not the same size as AST");
@ -550,16 +550,16 @@ struct AST_Friend
CodeComment InlineCmt;
char _PAD_PROPERTIES_[ sizeof(AST*) * 4 ];
Code Declaration;
char _PAD_PROPERTIES_2_[ sizeof(AST*) ];
char _PAD_PROPERTIES_2_[ sizeof(AST*) ];
};
};
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ];
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ];
};
static_assert( sizeof(AST_Friend) == sizeof(AST), "ERROR: AST_Friend is not the same size as AST");
@ -573,19 +573,19 @@ struct AST_Fn
CodeAttributes Attributes;
CodeSpecifiers Specs;
CodeTypename ReturnType;
CodeParams Params;
CodeParams Params;
CodeBody Body;
char _PAD_PROPERTIES_ [ sizeof(AST*) ];
char _PAD_PROPERTIES_ [ sizeof(AST*) ];
};
};
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
ModuleFlag ModuleFlags;
char _PAD_UNUSED_[ sizeof(u32) ];
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
ModuleFlag ModuleFlags;
char _PAD_UNUSED_[ sizeof(u32) ];
};
static_assert( sizeof(AST_Fn) == sizeof(AST), "ERROR: AST_Fn is not the same size as AST");
@ -594,14 +594,14 @@ struct AST_Module
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
};
StrCached Name;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
ModuleFlag ModuleFlags;
char _PAD_UNUSED_[ sizeof(u32) ];
char _PAD_UNUSED_[ sizeof(u32) ];
};
static_assert( sizeof(AST_Module) == sizeof(AST), "ERROR: AST_Module is not the same size as AST");
@ -610,45 +610,45 @@ struct AST_NS
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
struct {
char _PAD_PROPERTIES_[ sizeof(AST*) * 5 ];
char _PAD_PROPERTIES_[ sizeof(AST*) * 5 ];
CodeBody Body;
char _PAD_PROPERTIES_2_[ sizeof(AST*) ];
char _PAD_PROPERTIES_2_[ sizeof(AST*) ];
};
};
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
ModuleFlag ModuleFlags;
char _PAD_UNUSED_[ sizeof(u32) ];
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
ModuleFlag ModuleFlags;
char _PAD_UNUSED_[ sizeof(u32) ];
};
static_assert( sizeof(AST_NS) == sizeof(AST), "ERROR: AST_NS is not the same size as AST");
struct AST_Operator
{
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
struct
{
CodeComment InlineCmt;
CodeAttributes Attributes;
CodeSpecifiers Specs;
CodeTypename ReturnType;
CodeParams Params;
CodeBody Body;
char _PAD_PROPERTIES_ [ sizeof(AST*) ];
CodeComment InlineCmt;
CodeAttributes Attributes;
CodeSpecifiers Specs;
CodeTypename ReturnType;
CodeParams Params;
CodeBody Body;
char _PAD_PROPERTIES_ [ sizeof(AST*) ];
};
};
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
ModuleFlag ModuleFlags;
Operator Op;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
ModuleFlag ModuleFlags;
Operator Op;
};
static_assert( sizeof(AST_Operator) == sizeof(AST), "ERROR: AST_Operator is not the same size as AST");
@ -658,22 +658,22 @@ struct AST_OpCast
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
struct
{
CodeComment InlineCmt;
char _PAD_PROPERTIES_[ sizeof(AST*) ];
CodeSpecifiers Specs;
CodeTypename ValueType;
char _PAD_PROPERTIES_2_[ sizeof(AST*) ];
CodeBody Body;
char _PAD_PROPERTIES_3_[ sizeof(AST*) ];
CodeComment InlineCmt;
char _PAD_PROPERTIES_[ sizeof(AST*) ];
CodeSpecifiers Specs;
CodeTypename ValueType;
char _PAD_PROPERTIES_2_[ sizeof(AST*) ];
CodeBody Body;
char _PAD_PROPERTIES_3_[ sizeof(AST*) ];
};
};
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ];
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ];
};
static_assert( sizeof(AST_OpCast) == sizeof(AST), "ERROR: AST_OpCast is not the same size as AST");
@ -684,7 +684,7 @@ struct AST_Params
struct
{
// TODO(Ed): Support attributes for parameters (Some prefix macros can be converted to that...)
char _PAD_PROPERTIES_2_[ sizeof(AST*) * 3 ];
char _PAD_PROPERTIES_2_[ sizeof(AST*) * 3 ];
CodeTypename ValueType;
Code Macro;
Code Value;
@ -692,14 +692,14 @@ struct AST_Params
// char _PAD_PROPERTIES_3_[sizeof( AST* )];
};
};
StrCached Name;
CodeParams Last;
CodeParams Next;
Token* Tok;
Code Parent;
CodeType Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) ];
s32 NumEntries;
StrCached Name;
CodeParams Last;
CodeParams Next;
Token* Tok;
Code Parent;
CodeType Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) ];
s32 NumEntries;
};
static_assert( sizeof(AST_Params) == sizeof(AST), "ERROR: AST_Params is not the same size as AST");
@ -709,13 +709,13 @@ struct AST_Pragma
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
StrCached Content;
};
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ];
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ];
};
static_assert( sizeof(AST_Pragma) == sizeof(AST), "ERROR: AST_Pragma is not the same size as AST");
@ -723,40 +723,40 @@ struct AST_PreprocessCond
{
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
StrCached Content;
StrCached Content;
};
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ];
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ];
};
static_assert( sizeof(AST_PreprocessCond) == sizeof(AST), "ERROR: AST_PreprocessCond is not the same size as AST");
struct AST_Specifiers
{
Specifier ArrSpecs[ AST_ArrSpecs_Cap ];
Specifier ArrSpecs[ AST_ArrSpecs_Cap ];
StrCached Name;
CodeSpecifiers NextSpecs;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) ];
s32 NumEntries;
CodeSpecifiers NextSpecs;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) ];
s32 NumEntries;
};
static_assert( sizeof(AST_Specifiers) == sizeof(AST), "ERROR: AST_Specifier is not the same size as AST");
#if GEN_EXECUTION_EXPRESSION_SUPPORT
#ifdef GEN_EXECUTION_EXPRESSION_SUPPORT
struct AST_Stmt
{
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
};
StrCached Name;
StrCached Name;
CodeExpr Prev;
CodeExpr Next;
Token* Tok;
@ -771,7 +771,7 @@ struct AST_Stmt_Break
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
};
StrCached Name;
StrCached Name;
CodeExpr Prev;
CodeExpr Next;
Token* Tok;
@ -786,7 +786,7 @@ struct AST_Stmt_Case
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
};
StrCached Name;
StrCached Name;
CodeExpr Prev;
CodeExpr Next;
Token* Tok;
@ -801,7 +801,7 @@ struct AST_Stmt_Continue
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
};
StrCached Name;
StrCached Name;
CodeExpr Prev;
CodeExpr Next;
Token* Tok;
@ -816,7 +816,7 @@ struct AST_Stmt_Decl
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
};
StrCached Name;
StrCached Name;
CodeExpr Prev;
CodeExpr Next;
Token* Tok;
@ -831,7 +831,7 @@ struct AST_Stmt_Do
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
};
StrCached Name;
StrCached Name;
CodeExpr Prev;
CodeExpr Next;
Token* Tok;
@ -846,7 +846,7 @@ struct AST_Stmt_Expr
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
};
StrCached Name;
StrCached Name;
CodeExpr Prev;
CodeExpr Next;
Token* Tok;
@ -861,7 +861,7 @@ struct AST_Stmt_Else
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
};
StrCached Name;
StrCached Name;
CodeExpr Prev;
CodeExpr Next;
Token* Tok;
@ -876,7 +876,7 @@ struct AST_Stmt_If
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
};
StrCached Name;
StrCached Name;
CodeExpr Prev;
CodeExpr Next;
Token* Tok;
@ -891,7 +891,7 @@ struct AST_Stmt_For
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
};
StrCached Name;
StrCached Name;
CodeExpr Prev;
CodeExpr Next;
Token* Tok;
@ -906,7 +906,7 @@ struct AST_Stmt_Goto
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
};
StrCached Name;
StrCached Name;
CodeExpr Prev;
CodeExpr Next;
Token* Tok;
@ -921,7 +921,7 @@ struct AST_Stmt_Label
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
};
StrCached Name;
StrCached Name;
CodeExpr Prev;
CodeExpr Next;
Token* Tok;
@ -936,7 +936,7 @@ struct AST_Stmt_Switch
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
};
StrCached Name;
StrCached Name;
CodeExpr Prev;
CodeExpr Next;
Token* Tok;
@ -951,7 +951,7 @@ struct AST_Stmt_While
union {
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
};
StrCached Name;
StrCached Name;
CodeExpr Prev;
CodeExpr Next;
Token* Tok;
@ -970,14 +970,14 @@ struct AST_Struct
{
CodeComment InlineCmt;
CodeAttributes Attributes;
char _PAD_SPECS_ [ sizeof(AST*) ];
char _PAD_SPECS_ [ sizeof(AST*) ];
CodeTypename ParentType;
char _PAD_PARAMS_[ sizeof(AST*) ];
char _PAD_PARAMS_[ sizeof(AST*) ];
CodeBody Body;
char _PAD_PROPERTIES_2_[ sizeof(AST*) ];
char _PAD_PROPERTIES_2_[ sizeof(AST*) ];
};
};
StrCached Name;
StrCached Name;
CodeTypename Prev;
CodeTypename Next;
Token* Tok;
@ -994,20 +994,20 @@ struct AST_Template
char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ];
struct
{
char _PAD_PROPERTIES_[ sizeof(AST*) * 4 ];
char _PAD_PROPERTIES_[ sizeof(AST*) * 4 ];
CodeParams Params;
Code Declaration;
char _PAD_PROPERTIES_2_[ sizeof(AST*) ];
char _PAD_PROPERTIES_2_[ sizeof(AST*) ];
};
};
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
ModuleFlag ModuleFlags;
char _PAD_UNUSED_[ sizeof(u32) ];
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
ModuleFlag ModuleFlags;
char _PAD_UNUSED_[ sizeof(u32) ];
};
static_assert( sizeof(AST_Template) == sizeof(AST), "ERROR: AST_Template is not the same size as AST");
@ -1029,13 +1029,13 @@ struct AST_Type
// CodeSpecifiers SpecsFuncSuffix; // Only used for function signatures
};
};
StrCached Name;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Token* Tok;
Code Parent;
CodeType Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) ];
char _PAD_UNUSED_[ sizeof(ModuleFlag) ];
b32 IsParamPack;
};
static_assert( sizeof(AST_Type) == sizeof(AST), "ERROR: AST_Type is not the same size as AST");
@ -1062,7 +1062,7 @@ struct AST_Typename
Token* Tok;
Code Parent;
CodeType Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) ];
char _PAD_UNUSED_[ sizeof(ModuleFlag) ];
struct {
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)
@ -1077,9 +1077,9 @@ struct AST_Typedef
struct
{
CodeComment InlineCmt;
char _PAD_PROPERTIES_[ sizeof(AST*) * 2 ];
char _PAD_PROPERTIES_[ sizeof(AST*) * 2 ];
Code UnderlyingType;
char _PAD_PROPERTIES_2_[ sizeof(AST*) * 3 ];
char _PAD_PROPERTIES_2_[ sizeof(AST*) * 3 ];
};
};
StrCached Name;
@ -1101,19 +1101,19 @@ struct AST_Union
{
char _PAD_INLINE_CMT_[ sizeof(AST*) ];
CodeAttributes Attributes;
char _PAD_PROPERTIES_[ sizeof(AST*) * 3 ];
char _PAD_PROPERTIES_[ sizeof(AST*) * 3 ];
CodeBody Body;
char _PAD_PROPERTIES_2_[ sizeof(AST*) ];
char _PAD_PROPERTIES_2_[ sizeof(AST*) ];
};
};
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
ModuleFlag ModuleFlags;
char _PAD_UNUSED_[ sizeof(u32) ];
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
ModuleFlag ModuleFlags;
char _PAD_UNUSED_[ sizeof(u32) ];
};
static_assert( sizeof(AST_Union) == sizeof(AST), "ERROR: AST_Union is not the same size as AST");
@ -1125,19 +1125,19 @@ struct AST_Using
{
CodeComment InlineCmt;
CodeAttributes Attributes;
char _PAD_SPECS_ [ sizeof(AST*) ];
char _PAD_SPECS_ [ sizeof(AST*) ];
CodeTypename UnderlyingType;
char _PAD_PROPERTIES_[ sizeof(AST*) * 3 ];
char _PAD_PROPERTIES_[ sizeof(AST*) * 3 ];
};
};
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
ModuleFlag ModuleFlags;
char _PAD_UNUSED_[ sizeof(u32) ];
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
ModuleFlag ModuleFlags;
char _PAD_UNUSED_[ sizeof(u32) ];
};
static_assert( sizeof(AST_Using) == sizeof(AST), "ERROR: AST_Using is not the same size as AST");
@ -1153,17 +1153,17 @@ struct AST_Var
CodeTypename ValueType;
Code BitfieldSize;
Code Value;
CodeVar NextVar;
CodeVar NextVar;
};
};
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
ModuleFlag ModuleFlags;
s32 VarParenthesizedInit;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
ModuleFlag ModuleFlags;
s32 VarParenthesizedInit;
};
static_assert( sizeof(AST_Var) == sizeof(AST), "ERROR: AST_Var is not the same size as AST");

View File

@ -362,7 +362,7 @@ struct CodeExec
AST_Exec *ast;
};
#if GEN_EXECUTION_EXPRESSION_SUPPORT
#ifdef GEN_EXECUTION_EXPRESSION_SUPPORT
struct CodeExpr
{
#if ! GEN_C_LIKE_CPP
@ -689,7 +689,7 @@ struct CodePreprocessCond
AST_PreprocessCond* ast;
};
#if GEN_EXECUTION_EXPRESSION_SUPPORT
#ifdef GEN_EXECUTION_EXPRESSION_SUPPORT
struct CodeStmt
{
#if ! GEN_C_LIKE_CPP

View File

@ -72,7 +72,18 @@ inline Str spec_to_str( Specifier type )
inline bool spec_is_trailing( Specifier specifier )
{
return specifier > Spec_Virtual;
switch ( specifier )
{
case Spec_Const :
case Spec_Final :
case Spec_NoExceptions :
case Spec_Override :
case Spec_Pure :
case Spec_Volatile :
return true;
default :
return false;
}
}
inline Specifier str_to_specifier( Str str )

View File

@ -327,8 +327,6 @@ forceinline CodeBody def_union_body ( s32 num, Code* codes )
#pragma region Parsing
// TODO(Ed) : Implmeent the new parser API design.
#if 0
struct StackNode
{

View File

@ -987,7 +987,7 @@ CodeBody parse_class_struct_body( TokType which, Token name )
// <Attributes>
}
//! Fallthrough intended
GEN_PARSER_CLASS_STRUCT_BODY_ALLOWED_MEMBER_TOK_SPECIFIERS_CASES:
GEN_PARSER_CLASS_STRUCT_BODY_ALLOWED_MEMBER_TOK_SPECIFIER_CASES:
{
Specifier specs_found[16] = { Spec_NumSpecifiers };
s32 NumSpecifiers = 0;
@ -1000,7 +1000,7 @@ CodeBody parse_class_struct_body( TokType which, Token name )
switch ( spec )
{
GEN_PARSER_CLASS_STRUCT_BODY_ALLOWED_MEMBER_SPECIFIERS_CASES:
GEN_PARSER_CLASS_STRUCT_BODY_ALLOWED_MEMBER_SPECIFIER_CASES:
break;
case Spec_Consteval:
@ -3684,9 +3684,6 @@ CodeEnum parser_parse_enum( bool inplace_def )
Code array_expr = { nullptr };
CodeTypename type = { nullptr };
char entries_code[ kilobytes(128) ] = { 0 };
s32 entries_length = 0;
bool is_enum_class = false;
eat( Tok_Decl_Enum );
@ -3993,7 +3990,7 @@ CodeFriend parser_parse_friend()
switch ( spec )
{
GEN_PARSER_FRIEND_ALLOWED_SPECIFIERS_CASES:
GEN_PARSER_FRIEND_ALLOWED_SPECIFIER_CASES:
break;
default :
@ -4111,7 +4108,7 @@ CodeFn parser_parse_function()
switch ( spec )
{
GEN_PARSER_FUNCTION_ALLOWED_SPECIFIERS_CASES:
GEN_PARSER_FUNCTION_ALLOWED_SPECIFIER_CASES:
break;
default:
@ -4133,13 +4130,6 @@ CodeFn parser_parse_function()
}
// <export> <Attributes> <Specifiers>
// Note(Ed): We're enforcing that using this codepath requires non-macro jank.
// Code macro_stmt = parse_macro_as_definiton(attributes, specifiers);
// if (macro_stmt) {
// parser_pop(& _ctx->parser);
// return macro_stmt;
// }
CodeTypename ret_type = parser_parse_type(parser_not_from_template, nullptr);
if ( cast(Code, ret_type) == Code_Invalid ) {
parser_pop(& _ctx->parser);
@ -4219,7 +4209,7 @@ CodeOperator parser_parse_operator()
switch ( spec )
{
GEN_PARSER_OPERATOR_ALLOWED_SPECIFIERS_CASES:
GEN_PARSER_OPERATOR_ALLOWED_SPECIFIER_CASES:
break;
default:
@ -4452,7 +4442,7 @@ CodeTemplate parser_parse_template()
switch ( spec )
{
GEN_PARSER_TEMPLATE_ALLOWED_SPECIFIERS_CASES:
GEN_PARSER_TEMPLATE_ALLOWED_SPECIFIER_CASES:
break;
case Spec_Consteval :
@ -4691,11 +4681,12 @@ else if ( currtok.Type == Tok_DeclType )
}
}
}
// TODO(Ed): This needs updating
else if ( currtok.Type == Tok_Preprocess_Macro_Typename ) {
// Typename is a macro
name = currtok;
eat(Tok_Preprocess_Macro_Typename);
// name = currtok;
// eat(Tok_Preprocess_Macro_Typename);
Code macro = parse_simple_preprocess(Tok_Preprocess_Macro_Typename);
name.Text = macro->Content;
}
// The usual Identifier type signature that may have namespace qualifiers
@ -4741,7 +4732,7 @@ else if ( currtok.Type == Tok_DeclType )
// For function type signatures
CodeTypename return_type = NullCode;
CodeParams params = NullCode;
CodeParams params = NullCode;
#ifdef GEN_USE_NEW_TYPENAME_PARSING
CodeParams params_nested = NullCode;

View File

@ -1,6 +1,6 @@
// These macros are used in the swtich cases within parser.cpp
#define GEN_PARSER_CLASS_STRUCT_BODY_ALLOWED_MEMBER_TOK_SPECIFIERS_CASES \
#define GEN_PARSER_CLASS_STRUCT_BODY_ALLOWED_MEMBER_TOK_SPECIFIER_CASES \
case Tok_Spec_Consteval: \
case Tok_Spec_Constexpr: \
case Tok_Spec_Constinit: \
@ -13,7 +13,7 @@ case Tok_Spec_Static: \
case Tok_Spec_Volatile: \
case Tok_Spec_Virtual
#define GEN_PARSER_CLASS_STRUCT_BODY_ALLOWED_MEMBER_SPECIFIERS_CASES \
#define GEN_PARSER_CLASS_STRUCT_BODY_ALLOWED_MEMBER_SPECIFIER_CASES \
case Spec_Constexpr: \
case Spec_Constinit: \
case Spec_Explicit: \
@ -50,12 +50,12 @@ case Spec_NeverInline: \
case Spec_Static: \
case Spec_Volatile
#define GEN_PARSER_FRIEND_ALLOWED_SPECIFIERS_CASES \
#define GEN_PARSER_FRIEND_ALLOWED_SPECIFIER_CASES \
case Spec_Const: \
case Spec_Inline: \
case Spec_ForceInline
#define GEN_PARSER_FUNCTION_ALLOWED_SPECIFIERS_CASES \
#define GEN_PARSER_FUNCTION_ALLOWED_SPECIFIER_CASES \
case Spec_Const: \
case Spec_Consteval: \
case Spec_Constexpr: \
@ -66,7 +66,7 @@ case Spec_Inline: \
case Spec_NeverInline: \
case Spec_Static
#define GEN_PARSER_OPERATOR_ALLOWED_SPECIFIERS_CASES \
#define GEN_PARSER_OPERATOR_ALLOWED_SPECIFIER_CASES \
case Spec_Const: \
case Spec_Constexpr: \
case Spec_ForceInline: \
@ -74,7 +74,7 @@ case Spec_Inline: \
case Spec_NeverInline: \
case Spec_Static
#define GEN_PARSER_TEMPLATE_ALLOWED_SPECIFIERS_CASES \
#define GEN_PARSER_TEMPLATE_ALLOWED_SPECIFIER_CASES \
case Spec_Const: \
case Spec_Constexpr: \
case Spec_Constinit: \

View File

@ -132,8 +132,6 @@ enum MacroType : u16
MT_Expression, // A macro is assumed to be a expression if not resolved.
MT_Statement,
MT_Typename,
MT_Attribute, // More of a note to the parser than anythign else (attributes should be defined in the user attribues def).
MT_Specifier, // More of a note to the parser than anythign else (specifiers should be defined in the user attribues def).
MT_Block_Start, // Not Supported yet
MT_Block_End, // Not Supported yet
MT_Case_Statement, // Not Supported yet
@ -160,8 +158,6 @@ Str macrotype_to_str( MacroType type )
{ "Statement", sizeof("Statement") - 1 },
{ "Expression", sizeof("Expression") - 1 },
{ "Typename", sizeof("Typename") - 1 },
{ "Attribute(Macro)", sizeof("Attribute(Macro)") - 1 },
{ "Specifier(Macro)", sizeof("Specifier(Macro)") - 1 },
{ "Block_Start", sizeof("Block_Start") - 1 },
{ "Block_End", sizeof("Block_End") - 1 },
{ "Case_Statement", sizeof("Case_Statement") - 1 },

View File

@ -214,7 +214,18 @@ CodeBody gen_especifier( char const* path, bool use_c_definition = false )
inline
bool spec_is_trailing( Specifier specifier )
{
return specifier > Spec_Virtual;
switch (specifier) {
case Spec_Const:
case Spec_Final:
case Spec_NoExceptions:
case Spec_Override:
case Spec_Pure:
case Spec_Volatile:
return true;
default:
return false;
}
}
)));

View File

@ -53,6 +53,7 @@ StrBuilder <prefix>_to_strbuilder(Code code);
Where the first generates strings allocated using Allocator_StringArena and the other appends an existing strings with their backed allocator.
Serialization of for the AST is defined for `Code` in [`ast.chpp`](../base/components/ast.cpp) with `code_to_strbuilder_ptr` & `code_to_strbuilder`.
Serialization of for the AST is defined for `Code` in [`ast.cpp`](../base/components/ast.cpp) with `code_to_strbuilder_ptr` & `code_to_strbuilder`.
Serializtion for the rest of the code types is within [`code_serialization.cpp`](../base/components/code_serialization.cpp).
Gencpp's serialization does not provide coherent formatting of the code. The user should use a formatter after serializing.

View File

@ -25,13 +25,13 @@ These are containers representing a scope body of a definition that can be of th
Fields:
```cpp
StrCached Name;
Code Front;
Code Back;
Token* Tok;
Code Parent;
CodeT Type;
s32 NumEntries;
StrCached Name;
Code Front;
Code Back;
Token* Tok;
Code Parent;
CodeType Type;
s32 NumEntries;
```
The `Front` member represents the start of the link list and `Back` the end.
@ -56,13 +56,13 @@ Represent standard or vendor specific C/C++ attributes.
Fields:
```cpp
StrCached Content;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeT Type;
StrCached Content;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
```
Serialization:
@ -80,13 +80,13 @@ Stores a comment.
Fields:
```cpp
StrCached Content;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeT Type;
StrCached Content;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
```
Serialization:
@ -109,12 +109,12 @@ CodeComment InlineCmt; // Only supported by forward declarations
CodeAttributes Attributes;
CodeType ParentType;
CodeBody Body;
StrCached Name;
StrCached Name;
CodeType Prev;
CodeType Next;
Token* Tok;
Code Parent;
CodeT Type;
CodeType Type;
ModuleFlag ModuleFlags;
AccessSpec ParentAccess;
```
@ -139,16 +139,16 @@ You'll notice that only one parent type is supported only with parent access. Th
Fields:
```cpp
CodeComment InlineCmt; // Only supported by forward declarations
Code InitializerList;
CodeParams Params;
Code Body;
CodeComment InlineCmt; // Only supported by forward declarations
Code InitializerList;
CodeParams Params;
Code Body;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeT Type;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
```
Serialization:
@ -178,13 +178,14 @@ Represents a preprocessor define
Fields:
```cpp
StrCached Content;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeT Type;
CodeDefineParams Params;
Code Body;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
```
Serialization:
@ -193,6 +194,28 @@ Serialization:
#define <Name> <Content>
```
## DefineParams
Preprocessor define's parameters.
Fields:
```cpp
StrCached Name;
Code Last;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
s32 NumEntries;
```
Serialization:
```cpp
<Name>, <Next> ...
```
## Destructor
Fields:
@ -201,12 +224,12 @@ Fields:
CodeComment InlineCmt;
CodeSpecifiers Specs;
Code Body;
StrCached Name;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeT Type;
CodeType Type;
```
Serialization:
@ -242,8 +265,8 @@ Code Prev;
Code Next;
Token* Tok;
Code Parent;
StrCached Name;
CodeT Type;
StrCached Name;
CodeType Type;
ModuleFlag ModuleFlags;
```
@ -271,13 +294,13 @@ Will be obsolute when function body parsing is implemented.
Fields:
```cpp
StrCached Content;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeT Type;
StrCached Content;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
```
Serialization:
@ -286,18 +309,18 @@ Serialization:
<Content>
```
## External Linkage
## External Linkage (Extern)
Fields:
```cpp
CodeBody Body;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeT Type;
CodeBody Body;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
```
Serialization:
@ -314,13 +337,13 @@ extern "<Name>"
Fields:
```cpp
StrCached Content;
StrCached Name;
Code Prev;
Code Next;
Code Parent;
Token* Tok;
CodeT Type;
StrCached Content;
StrCached Name;
Code Prev;
Code Next;
Code Parent;
Token* Tok;
CodeType Type;
```
Serialization:
@ -336,14 +359,14 @@ This library (until its necessary become some third-party library to do otherwis
Fields:
```cpp
CodeComment InlineCmt;
Code Declaration;
CodeComment InlineCmt;
Code Declaration;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeT Type;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
```
Serialization:
@ -363,12 +386,12 @@ CodeSpecifiers Specs;
CodeType ReturnType;
CodeParams Params;
CodeBody Body;
StrCached Name;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeT Type;
CodeType Type;
ModuleFlag ModuleFlags;
```
@ -390,13 +413,13 @@ Serialization:
Fields:
```cpp
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeT Type;
ModuleFlag ModuleFlags;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
ModuleFlag ModuleFlags;
```
Serialization:
@ -410,14 +433,14 @@ Serialization:
Fields:
```cpp
CodeBody Body;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeT Type;
ModuleFlag ModuleFlags;
CodeBody Body;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
ModuleFlag ModuleFlags;
```
Serialization:
@ -440,12 +463,12 @@ CodeSpecifiers Specs;
CodeType ReturnType;
CodeParams Params;
CodeBody Body;
StrCached Name;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeT Type;
CodeType Type;
ModuleFlag ModuleFlags;
OperatorT Op;
```
@ -472,12 +495,12 @@ CodeComment InlineCmt;
CodeSpecifiers Specs;
CodeType ValueType;
CodeBody Body;
StrCached Name;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeT Type;
CodeType Type;
```
Serialization:
@ -498,17 +521,17 @@ Serialization:
Fields:
```cpp
CodeType ValueType;
Code Macro;
Code Value;
Code PostNameMacro;
StrCached Name;
CodeParams Last;
CodeParams Next;
Token* Tok;
Code Parent;
CodeT Type;
s32 NumEntries;
CodeType ValueType;
Code Macro;
Code Value;
Code PostNameMacro;
StrCached Name;
CodeParams Last;
CodeParams Next;
Token* Tok;
Code Parent;
CodeType Type;
s32 NumEntries;
```
Serialization:
@ -524,13 +547,13 @@ Serialization:
Fields:
```cpp
StrCached Content;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeT Type;
StrCached Content;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
```
Serialization:
@ -544,13 +567,13 @@ Serialization:
Fields:
```cpp
StrCached Content;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeT Type;
StrCached Content;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
```
Serialization:
@ -566,12 +589,12 @@ Fields:
```cpp
SpecifierT ArrSpecs[ AST_ArrSpecs_Cap ];
CodeSpecifiers NextSpecs;
StrCached Name;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeT Type;
CodeType Type;
s32 NumEntries;
```
@ -586,15 +609,15 @@ Serialization:
Fields:
```cpp
CodeParams Params;
Code Declaration;
CodeParams Params;
Code Declaration;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeT Type;
ModuleFlag ModuleFlags;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeType Type;
ModuleFlag ModuleFlags;
```
Serialization:
@ -621,8 +644,8 @@ Code Prev;
Code Next;
Token* Tok;
Code Parent;
StrCached Name;
CodeT Type;
StrCached Name;
CodeType Type;
b32 IsParamPack;
ETypenameTag TypeTag;
```
@ -647,16 +670,16 @@ Those (macros) don't use the underlying type field as everything was serialized
Fields:
```cpp
CodeComment InlineCmt;
Code UnderlyingType;
StrCached Name;
Code Prev;
Code Next;
Token* Tok
Code Parent;
CodeT Type;
ModuleFlag ModuleFlags;
b32 IsFunction;
CodeComment InlineCmt;
Code UnderlyingType;
StrCached Name;
Code Prev;
Code Next;
Token* Tok
Code Parent;
CodeType Type;
ModuleFlag ModuleFlags;
b32 IsFunction;
```
Serialization:
@ -682,12 +705,12 @@ Fields:
```cpp
CodeAttributes Attributes;
CodeBody Body;
StrCached Name;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeT Type;
CodeType Type;
ModuleFlag ModuleFlags;
```
@ -708,12 +731,12 @@ Fields:
CodeComment InlineCmt;
CodeAttributes Attributes;
CodeType UnderlyingType;
StrCached Name;
StrCached Name;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeT Type;
CodeType Type;
ModuleFlag ModuleFlags;
```
@ -740,13 +763,13 @@ CodeSpecifiers Specs;
CodeType ValueType;
Code BitfieldSize;
Code Value;
StrCached Name;
StrCached Name;
CodeVar NextVar;
Code Prev;
Code Next;
Token* Tok;
Code Parent;
CodeT Type;
CodeType Type;
ModuleFlag ModuleFlags;
s32 VarParenthesizedInit;
```

File diff suppressed because it is too large Load Diff

View File

@ -6,9 +6,9 @@
# Parsing
The library features a naive single-pass parser tailored for only what the library needs to construct the supported syntax of C++ into its AST for *"front-end"* meta-programming purposes.
The library features a naive single-pass parser, tailored for only what the library needs; for construction of C++ code into gencpp's AST for *"front-end"* meta-programming purposes.
This parser does not, and should not do the compiler's job. By only supporting this minimal set of features, the parser is kept (so far) around ~7000 loc. I hope to keep it under 10k loc worst case.
This parser does not, and should not do the compiler's job. By only supporting this minimal set of features, the parser is kept (so far) around ~7000 loc. I hope to keep it under 10-15k loc worst case.
You can think of this parser as *frontend parser* vs a *semantic parser*. Its intuitively similar to WYSIWYG. What you ***precerive*** as the syntax from the user-side before the compiler gets a hold of it, is what you get.
@ -17,6 +17,7 @@ User exposed interface:
```cpp
CodeClass parse_class ( Str class_def );
CodeConstructor parse_constructor ( Str constructor_def );
CodeDefine parse_define ( Str define_def );
CodeDestructor parse_destructor ( Str destructor_def );
CodeEnum parse_enum ( Str enum_def );
CodeBody parse_export_body ( Str export_def );
@ -53,38 +54,98 @@ The keywords supported for the preprocessor are:
* endif
* pragma
Each directive `#` line is considered one preproecessor unit, and will be treated as one Preprocessor AST.
Each directive `#` line is considered one preproecessor unit, and will be treated as one Preprocessor AST node.
If a directive is used with an unsupported keyword its will be processed as an untyped AST.
The preprocessor lines are stored as members of their associated scope they are parsed within. ( Global, Namespace, Class/Struct )
***Again (Its not standard): These ASTs will be considered members or entries of braced scope they reside within***
The preprocessor lines are stored as members of their associated scope they are parsed within ( Global, Namespace, Class/Struct ).
***Again: These ASTs will be considered members or entries of braced scope they reside within***
Any preprocessor definition abuse that changes the syntax of the core language is unsupported and will fail to parse if not kept within an execution scope (function body, or expression assignment).
Exceptions:
* function signatures are allowed for a preprocessed macro: `neverinline MACRO() { ... }`
* varaible definitions are allowed for a preprocessed macro `extern MACRO();`
* function definitions are allowed for a preprocessed macro: `neverinline MACRO() { ... }`
* Disable with: `#define GEN_PARSER_DISABLE_MACRO_FUNCTION_SIGNATURES`
* typedefs allow for a preprocessed macro: `typedef MACRO();`
* Disable with: `#define GEN_PARSER_DISABLE_MACRO_TYPEDEF`
* Macros can behave as typenames
* There is some macro support in paramters for functions or templates *(Specifically added to support parsing Unreal Engine source)*.
* There is some macro support in parameters for functions or templates *(Specifically added to support parsing Unreal Engine source)*.
*(Exceptions are added on an on-demand basis)*
*(See functions `parse_operator_function_or_variable` and `parse_typedef` )*
Adding your own exceptions is possible by simply modifying the parser to allow for the syntax you need.
*Note: You could interpret this strictness as a feature. This would allow the user to see if their codebase or a third-party's codebase some some egregious preprocessor abuse.*
*Note: You could interpret this strictness as a feature. This would allow the user to see if their codebase or a third-party's codebase contains some egregious preprocessor abuse.*
If a macro is not defined withint e scope of parsing a set of files, it can be defined beforehand by:
Macros used within a file should be registered by the user before parsing. This can be done two ways:
* Appending the [`PreprocessorDefines`](https://github.com/Ed94/gencpp/blob/a18b5b97aa5cfd20242065cbf53462a623cd18fa/base/components/header_end.hpp#L137) array.
* For functional macros a "(" just needs to be added after the name like: `<name>(` so that it will tokenize its arguments as part of the token during lexing.
* Defining a CodeDefine using `def_define`. The definition will be processed by the interface for user into `PreprocessorDefines`.
* This can be prevented by setting the optional prameter `dont_append_preprocess_defines`.
1. The register macro interface within [interface.hpp](../base/components/interface.hpp).
2. Using `def_define` to create a CodeDefine and making sure to not set `opts.dont_register_to_preprocess_macros` to `true`.
The lexing and parsing takes shortcuts from whats expected in the standard.
## Registering macros
While the registeration of macros in the meta-program's side for parsing can be considered tedius, its necessary for the parser to accurately resolve the macros intent in one pass (and it provides some hygenics by verifying that they are used as intended).
The following can be used to register a macro:
```c
GEN_API void register_macro( Macro macro );
GEN_API void register_macros( s32 num, ... );
GEN_API void register_macros_arr( s32 num, Macro* macros );
```
The Macro typename is defined with the following in [parser_types.hpp](../base/components/parser_types.hpp):
```c
struct Macro
{
StrCached Name;
MacroType Type;
MacroFlags Flags;
};
```
The macro can be designated one of the following types:
* `MT_Expression`: Intended to resolve to an expression expansion.
* `MT_Statement`: Intended to resolve an statement expansion.
* `MT_Typename`: Intended to resolve to a typename.
Additioonally tthe following flags may be set:
* `MF_Functional`: The macro intended to be passed arguments are at least have the calling `()` as part of its usage.
* `MF_Expects_Body`: The parser should expect a braced-body `{ ... }` after the macro signature `<name> <params>`
* `MF_Allow_As_Identifier`: Will allow the macro to be an acceptable token/s when an `Tok_Identifier` is expected.
* `MF_Allow_As_Attribute`: Will allow the macro to be an acceptable token/s when an attribute token/s is expected.
* `MF_Allow_As_Definition`: Will allow the macro be an acceptable token/s when the parser expects a declartion or definition to resolve after attributes or specifiers have been identified beforehand.
* This flag requires that the macro is of type `MT_Statement` to make any sense of usage.
If a macro is not defined the following warning will be issued if `GEN_BUILD_DEBUG=1` during lexing within [lexer.cpp](../base/components/lexer.cpp) - `lex_preprocessor_define`:
```c
log_fmt("Warning: '%S' was not registered before the lexer processed its #define directive, it will be registered as a expression macro\n"
, name.Text
);
```
Further within the same scope, the lexer will issue a warning if it detects a macro was not flagged as function but has an open parenthesis `(` token right after is name with no whitespace:
```c
log_fmt("Warning: %S registered macro is not flagged as functional yet the definition detects opening parenthesis '(' for arguments\n"
, name.Text
);
```
Macros are tracked using a `MacroTable Macros;` defined as a member of the library's `Context`.
```c
typedef HashTable(Macro) MacroTable;
```
## Notes
* Empty lines used throughout the file are preserved for formatting purposes during ast serialization (they have a dedicated Token: `Tok_NewLine`).
* Numeric literals are not checked for validity.
* The parse API treats any execution scope definitions with no validation and are turned into untyped Code ASTs. (There is a [todo](https://github.com/Ed94/gencpp/issues/49) to add support)
* *This includes the assignment of variables.*
@ -95,4 +156,4 @@ The lexing and parsing takes shortcuts from whats expected in the standard.
* Parsing attributes can be extended to support user defined macros by defining `GEN_DEFINE_ATTRIBUTE_TOKENS` (see `gen.hpp` for the formatting)
* This is useful for example: parsing Unreal `Module_API` macros.
Empty lines used throughout the file are preserved for formatting purposes during ast serialization.
**The lexer & parser do not gracefully attempt to continue when it comes across incorrect code, and doesn't properly track errors into a listing (yet).**

View File

@ -26,7 +26,7 @@ This means that the typename entry for the parameter AST would be either:
***Concepts and Constraints are not supported***
Its a [todo](https://github.com/Ed94/gencpp/issues/21)
### Feature Macros:
### Feature Macros
* `GEN_DEFINE_ATTRIBUTE_TOKENS` : Allows user to define their own attribute macros for use in parsing.
* This can be generated using base.cpp.
@ -36,10 +36,41 @@ Its a [todo](https://github.com/Ed94/gencpp/issues/21)
* `GEN_EXPOSE_BACKEND` : Will expose symbols meant for internal use only.
* `GEN_ROLL_OWN_DEPENDENCIES` : Optional override so that user may define the dependencies themselves.
* `GEN_DONT_ALLOW_INVALID_CODE` (Not implemented yet) : Will fail when an invalid code is constructed, parsed, or serialized.
* `GEN_C_LIKE_PP` : Setting to `<true or 1>` Will prevent usage of function defnitions using references and structs with member functions. Structs will still have user-defined operator conversions, for-range support, and other operator overloads
* `GEN_C_LIKE_CPP` : Setting to `<true or 1>` Will prevent usage of function defnitions using references and structs with member functions. Structs will still have user-defined operator conversions, for-range support, and other operator overloads
### The Data & Interface
The library's persistent state is managed tracked by a context struct: `global Context* _ctx;` defined within [static_data.cpp](../base/components/static_data.cpp)
https://github.com/Ed94/gencpp/blob/967a044637f1615c709cb723dc61118fcc08dcdb/base/components/interface.hpp#L39-L97
The interface for the context:
* `init`: Initializtion
* `deinit`: De-initialization.
* `reset`: Clears the allocations, but doesn't free the memoery, then calls `init()` on `_ctx` again.
* `get_context`: Retreive the currently tracked context.
* `set_context`: Swap out the current tracked context.
#### Allocato usage
* `Allocator_DyanmicContainers`: Growing arrays, hash tables. (Unbounded sized containers)
* `Allocator_Pool`: Fixed-sized object allocations (ASTs, etc)
* `Allocator_StrCache`: StrCached allocations
* `Allocator_Temp`: Temporary alloations mostly intended for StrBuilder usage. Manually cleared by the user by their own discretion.
The allocator definitions used are exposed to the user incase they want to dictate memory usage
* Allocators are defined with the `AllocatorInfo` structure found in [`memory.hpp`](../base/dependencies/memory.hpp)
* Most of the work is just defining the allocation procedure:
```cpp
void* ( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags );
```
For any allocator above that the user does not define before `init`, a fallback allocator will be assigned that utiizes the `fallback_allocator_proc` wtihin [interface.cpp](../base/components/interface.cpp).
As mentioned in root readme, the user is provided Code objects by calling the constructor's functions to generate them or find existing matches.
The AST is managed by the library and provided to the user via its interface.
@ -47,14 +78,14 @@ However, the user may specifiy memory configuration.
[Data layout of AST struct (Subject to heavily change with upcoming todos)](../base/components/ast.hpp#L396-461)
https://github.com/Ed94/gencpp/blob/eea4ebf5c40d5d87baa465abfb1be30845b2377e/base/components/ast.hpp#L396-L461
https://github.com/Ed94/gencpp/blob/967a044637f1615c709cb723dc61118fcc08dcdb/base/components/ast.hpp#L369-L435
*`StringCahced` is a typedef for `Str` (a string slice), to denote it is an interned string*
*`CodeType` is enum taggin the type of code. Has an underlying type of `u32`*
*`OperatorT` is a typedef for `EOperator::Type` which has an underlying type of `u32`*
*`StrBuilder` is the dynamically allocated string type for the library*
*`StrBuilder` is the dynamically allocating string builder type for the library*
AST widths are setup to be AST_POD_Size.
AST widths are setup to be AST_POD_Size (128 bytes by default).
The width dictates how much the static array can hold before it must give way to using an allocated array:
```cpp
@ -73,41 +104,16 @@ int AST_ArrSpecs_Cap =
)
/ sizeof(Specifier) - 1;
```
*Ex: If the AST_POD_Size is 128 the capacity of the static array is 20.*
Data Notes:
* The allocator definitions used are exposed to the user incase they want to dictate memory usage
* You'll find the memory handling in `init`, `deinit`, `reset`, `gen_strbuilder_allocator`, `cache_str`, `make_code`.
* Allocators are defined with the `AllocatorInfo` structure found in [`memory.hpp`](../base/dependencies/memory.hpp)
* Most of the work is just defining the allocation procedure:
```cpp
void* ( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags );
```
* ASTs are wrapped for the user in a Code struct which is a wrapper for a AST* type.
* Code types have member symbols but their data layout is enforced to be POD types.
* This library treats memory failures as fatal.
* Cached Strings are stored in their own set of arenas. AST constructors use cached strings for names, and content.
* `StringArenas`, `StringCache`, `Allocator_StringArena`, and `Allocator_StringTable` are the associated containers or allocators.
* Strings used for serialization and file buffers are not contained by those used for cached strings.
* They are currently using `FallbackAllocator`, which are tracked array of arenas that grows as needed (adds buckets when one runs out).
* Memory within the buckets is not reused, so its inherently wasteful.
* I will be augmenting the default allocator with virtual memory & a slab allocator in the [future](https://github.com/Ed94/gencpp/issues/12)
* Intrusive linked lists used children nodes on bodies, and parameters.
* `_ctx->Allocator_Temp` is used.
* Its intended to generate the AST in one go and serialize after. The constructors and serializer are designed to be a "one pass, front to back" setup.
* Allocations can be tuned by defining the folloiwng macros (will be moved to runtime configuration in the future):
* `GEN_GLOBAL_BUCKET_SIZE` : Size of each bucket area for the global allocator
* `GEN_CODEPOOL_NUM_BLOCKS` : Number of blocks per code pool in the code allocator
* `GEN_SIZE_PER_STRING_ARENA` : Size per arena used with string caching.
* `GEN_MAX_COMMENT_LINE_LENGTH` : Longest length a comment can have per line.
* `GEN_MAX_NAME_LENGTH` : Max length of any identifier.
* `GEN_MAX_UNTYPED_STR_LENGTH` : Max content length for any untyped code.
* `TokenMap_FixedArena` : token_fmt_va uses local_persit memory of this arena type for the hashtable.
* `GEN_LEX_ALLOCATOR_SIZE`
* `GEN_BUILDER_STR_BUFFER_RESERVE`
* Any modifcations to an existing AST should be to just construct another with the modifications done on-demand while traversing the AST (non-destructive).
The following CodeTypes are used which the user may optionally use strong typing with if they enable: `GEN_ENFORCE_STRONG_CODE_TYPES`
@ -117,6 +123,7 @@ The following CodeTypes are used which the user may optionally use strong typing
* CodeClass
* CodeConstructor
* CodeDefine
* CodeDefineParams
* CodeDestructor
* CodeEnum
* CodeExec
@ -127,7 +134,7 @@ The following CodeTypes are used which the user may optionally use strong typing
* CodeModule
* CodeNS
* CodeOperator
* CodeOpCast
* CodeOpCast : User defined member operator conversion
* CodeParams : Has support for `for : range` iterating across parameters.
* CodePreprocessCond
* CodePragma
@ -140,11 +147,15 @@ The following CodeTypes are used which the user may optionally use strong typing
* CodeUsing
* CodeVar
Each Code boy has an associated "filtered AST" with the naming convention: `AST_<CodeName>`
Each `struct Code<Name>` has an associated "filtered AST" with the naming convention: `AST_<CodeName>`
Unrelated fields of the AST for that node type are omitted and only necessary padding members are defined otherwise.
Retrieving a raw version of the ast can be done using the `raw()` function defined in each AST.
## There are three sets of interfaces for Code AST generation the library provides
For the interface related to these code types see:
* [ast.hpp](../base/components/ast.hpp): Under the region pragma `Code C-Interface`
* [code_types.hpp](../base/components/code_types.hpp): Under the region pragma `Code C-Interface`. Additional functionlity for c++ will be within the struct definitions or at the end of the file.
## There are three categories of interfaces for Code AST generation & reflection
* Upfront
* Parsing
@ -164,6 +175,7 @@ Interface :``
* def_class
* def_constructor
* def_define
* def_define_params
* def_destructor
* def_enum
* def_execution
@ -218,6 +230,27 @@ Code <name>
```
All optional parmeters are defined within `struct Opts_def_<functon name>`. This was done to setup a [macro trick](https://x.com/vkrajacic/status/1749816169736073295) for default optional parameers in the C library:
```cpp
struct gen_Opts_def_struct
{
gen_CodeBody body;
gen_CodeTypename parent;
gen_AccessSpec parent_access;
gen_CodeAttributes attributes;
gen_CodeTypename* interfaces;
gen_s32 num_interfaces;
gen_ModuleFlag mflags;
};
typedef struct gen_Opts_def_struct gen_Opts_def_struct;
GEN_API gen_CodeClass gen_def__struct( gen_Str name, gen_Opts_def_struct opts GEN_PARAM_DEFAULT );
#define gen_def_struct( name, ... ) gen_def__struct( name, ( gen_Opts_def_struct ) { __VA_ARGS__ } )
```
In the C++ library, the `def_<funtion name>` is not wrapped in a macro.
When using the body functions, its recommended to use the args macro to auto determine the number of arguments for the varadic:
```cpp
@ -228,7 +261,7 @@ def_global_body( 3, ht_entry, array_ht_entry, hashtable );
```
If a more incremental approach is desired for the body ASTs, `Code def_body( CodeT type )` can be used to create an empty body.
When the members have been populated use: `AST::validate_body` to verify that the members are valid entires for that type.
When the members have been populated use: `code_validate_body` to verify that the members are valid entires for that type.
### Parse construction
@ -244,7 +277,6 @@ Interface :
* parse_export_body
* parse_extern_link
* parse_friend
* Purposefully are only support forward declares with this constructor.
* parse_function
* parse_global_body
* parse_namespace

Binary file not shown.

View File

@ -1,7 +1,5 @@
## Navigation
# base
[Top](../Readme.md)
* [docs](../docs/Readme.md)
@ -15,9 +13,133 @@ The output will be in the `gen_segmented/gen` directory (if the directory does n
If using the library's provided build scripts:
```ps1
.\build.ps1 <compiler> <debug or omit> c_library
.\build.ps1 <compiler> <debug or omit> c_lib
```
To generate a static or dynamic library:
```ps1
.\build.ps1 <compiler> <debug or omit> c_lib_static c_lib_dyn
```
All free from tag identifiers will be prefixed with `gen_` or `GEN_` as the namespace. This can either be changed after generation with a `.refactor` script (or your preferred subst method), OR by modifying [c_library.refactor](./c_library.refactor).
**If c_library.refactor is modified you may need to modify c_library.cpp and its [components](./components/). As some of the container generation relies on that prefix.**
## Generation structure
1. Files are scanned in or parsed.
* If they are parsed, its dude to requiring some changes to either naming, or adding additonal definitions (container generation, typedefs, etc).
2. All scanned or parsed code is refactored (identifiers substs) and/or formatted.
3. Singleheader generated.
4. Segemented headers and source generated.
## Templated container generation
The array and hashtable containers used across this library are generated using the following implementatioon:
* [containers.array.hpp](./components/containers.array.hpp)
* [containers.hashtable.hpp](./components/containers.hashtable.hpp)
These are functionally (and interface wise) equivalent to the library's `Array<Type>` `HashTable<Type>` within [containers.hpp](../base/dependencies/containers.hpp)
Both files follow the same patter of providing three procedures:
* `gen_<container>_base` : Intended to be called once, defines universal "base" definitions.
* `gen_<container>` : Called per instatiation of the container for a given set of dependent args.
* `gen_<container>_generic_selection_interface` : Intended to be called once after all of the instantiated containers have finished generating. It will generate a set of generic selection macros as described by Macro Usage section below.
A simple `<container>_DefinitionCounter` is used to know how many instantiations of the template have occured. This is used to determine how to define `GENERIC_SLOT_<ID>_<functionID>` for the generic interface along with how many slots the `_Generic` macro will need to have generated.
## Macro Usage
For the most part macros are kept minimal with exception to `_Generic`...
*(I will be explaining this thing for the rest of this seciton along with gencpp c library's usage of it)*
The `_Generic` macro plays a key role in reducing direct need of the user to wrangle with mangled definition identifiers of 'templated' containers or for type coercion to map distinct data types to a common code path.
Because of its lack of use in many C11 libraries.. and, of those that do; they usually end up obfuscating it with excessive preprocessor abuse; Effort was put into minimizing how much of these macros are handled by the preprocessor vs gencpp itself.
The usual presentation (done bare) is the following:
```c
#define macro_that_selects_typeof_arg(arg, y) \
_Generic( (arg), \
int : some expression, \
double : some other expression, \
struct Whatnot : something else again, \
default : fallback expression \
)
```
Where `_Generic` can be considered the follwoing (psuedo-C):
```c
#define type_expr_pair(type, expr) type: expr
C_Expression _Generic( selector_arg, a_type_expr_pair, ... ) {
switch( typeof(selector_arg)) {
case a_type_expr_pair:
return a_type_expr_pari.expr;
...
default:
return default.expr;
}
}
```
The first `arg` of _Generic behaves as the "controlling expression" or the expression that resolves to a type which will dictate which of the following expressions provided after to `_Generic` will be resolved as the one used inline for the implemenation.
For this library's purposes we'll be using the functional macro equivalent *(if there is an exception I'll link it at the end of this section)*:
```c
#define macro_that_uses_selector_arg_for_resolving_a_fucntion( selecting_exp) \
_Generic( (arg), \
int : func_use_int, \
double : func_use_double, \
struct Whatnot : func_use_Whatnot, \
default : struct SIGNALS_FAILURE \
) (selecting_exp)
```
In this case, we directly added `(selecting_exp)` to the end there.. as we want to directly have the macro resolve to calling a resolved procedure. A default has been set to a struct as that leads to a neat compiler message that would otherwise be impossible beause static_assert is a statement and thus cannot be used within a slot.
Now, even with gencpp generating this type-expression table, we still need wrapper macros to achieve function 'overloading' for the templated containers as _Generic has a [significant drawback](https://www.chiark.greenend.org.uk/~sgtatham/quasiblog/c11-generic/):
> Discarded expressions still have to be semantically valid.
The only way to absolve this issue [(without resorting to nasty preprocessor hacks)](https://github.com/JacksonAllan/CC/blob/main/articles/Better_C_Generics_Part_1_The_Extendible_Generic.md) is with wrapping expressions in 'slot' resolving macros that do not expand if the slot is not defined:
```c
GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( GENERIC_SLOT_1__function_sig )
```
`GENERIC_SLOT_1__function_sig` is our warpper of a "`int, func_use_int`" pair. The `GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT` is a verbse named macro to indicate that that pair will be expanded ***ONLY IF*** its defined.
So for any given templated container interface. Expect the follwoing (taken straight from generation, and just cleaned up formatting):
```c
#define gen_array_append( selector_arg, ... ) _Generic( \
(selector_arg ), \
GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( GEN_GENERIC_SLOT_1__array_append ) \
GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( GEN_GENERIC_SLOT_2__array_append ) \
GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( GEN_GENERIC_SLOT_3__array_append ) \
GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( GEN_GENERIC_SLOT_4__array_append ) \
GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( GEN_GENERIC_SLOT_5__array_append ) \
GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( GEN_GENERIC_SLOT_6__array_append ) \
GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( GEN_GENERIC_SLOT_7__array_append ) \
GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( GEN_GENERIC_SLOT_8__array_append ) \
GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( GEN_GENERIC_SLOT_9__array_append ) \
GEN_IF_MACRO_DEFINED_INCLUDE_THIS_SLOT( GEN_GENERIC_SLOT_10__array_append ) \
default: gen_generic_selection_fail \
) GEN_RESOLVED_FUNCTION_CALL( &selector_arg, __VA_ARGS__ )
```
*Note(Ed): Unfortunately I cannot get clang-format to output these macros sanely like the above..*
*Eventually I'll add some basic builtin formatting but if the user has suggestions for something better I'm open ears...*
`GEN_RESOLVED_FUNCTION_CALL` is an empty define, its just to indicate that its intended to expand to a function call.
To see the the actual macro definitions used - see: [generic_macros.h](./components/generic_macros.h). They'll be injected right after the usual macros in the generated header file.

View File

@ -2,7 +2,6 @@
#define GEN_DEFINE_LIBRARY_CODE_CONSTANTS
#define GEN_ENFORCE_STRONG_CODE_TYPES
#define GEN_EXPOSE_BACKEND
#include "gen.cpp"
#include "helpers/push_ignores.inline.hpp"
@ -801,6 +800,9 @@ do \
b32 found = ignore_preprocess_cond_block(txt("GEN_INTELLISENSE_DIRECTIVES"), entry, parsed_ast, ast );
if (found) break;
found = ignore_preprocess_cond_block(txt("GEN_EXECUTION_EXPRESSION_SUPPORT"), entry, parsed_ast, ast );
if (found) break;
ast.append(entry);
}
break;
@ -979,6 +981,9 @@ R"(#define AST_ArrSpecs_Cap \
found = ignore_preprocess_cond_block(txt("GEN_INTELLISENSE_DIRECTIVES"), entry, parsed_code_types, code_types );
if (found) break;
found = ignore_preprocess_cond_block(txt("GEN_EXECUTION_EXPRESSION_SUPPORT"), entry, parsed_code_types, code_types);
if (found) break;
code_types.append(entry);
}
break;
@ -1073,7 +1078,10 @@ R"(#define <interface_name>( code ) _Generic( (code), \
case CT_Preprocess_If:
case CT_Preprocess_IfDef:
{
b32 found = ignore_preprocess_cond_block(txt("GEN_INTELLISENSE_DIRECTIVES"), entry, parsed_code_types, code_types );
b32 found = ignore_preprocess_cond_block(txt("GEN_INTELLISENSE_DIRECTIVES"), entry, parsed_ast_types, ast_types );
if (found) break;
found = ignore_preprocess_cond_block(txt("GEN_EXECUTION_EXPRESSION_SUPPORT"), entry, parsed_ast_types, ast_types);
if (found) break;
ast_types.append(entry);
@ -1121,6 +1129,7 @@ R"(#define <interface_name>( code ) _Generic( (code), \
CodeBody interface = def_body(CT_Global_Body);
for ( Code entry = parsed_interface.begin(); entry != parsed_interface.end(); ++ entry ) switch( entry->Type )
{
case CT_Preprocess_If:
case CT_Preprocess_IfDef:
{
b32 found = ignore_preprocess_cond_block(txt("GEN_INTELLISENSE_DIRECTIVES"), entry, parsed_interface, interface );
@ -1129,6 +1138,9 @@ R"(#define <interface_name>( code ) _Generic( (code), \
found = ignore_preprocess_cond_block(txt("GEN_COMPILER_CPP"), entry, parsed_interface, interface);
if (found) break;
found = ignore_preprocess_cond_block(txt("0"), entry, parsed_interface, interface);
if (found) break;
interface.append(entry);
}
break;
@ -1139,15 +1151,6 @@ R"(#define <interface_name>( code ) _Generic( (code), \
CodeFn fn = cast(CodeFn, entry);
Code prev = entry->Prev;
#if 0
if (prev && prev->Name.is_equal(entry->Name)) {
// rename second definition so there isn't a symbol conflict
StrBuilder postfix_arr = StrBuilder::fmt_buf(_ctx->Allocator_Temp, "%S_arr", entry->Name);
entry->Name = cache_str(postfix_arr.to_str());
postfix_arr.free();
}
#endif
b32 handled= false;
for ( CodeParams opt_param : fn->Params ) if (opt_param->ValueType->Name.starts_with(txt("Opts_")))
{
@ -1215,11 +1218,18 @@ R"(#define <interface_name>( code ) _Generic( (code), \
CodeBody inlines = def_body(CT_Global_Body);
for ( Code entry = parsed_inlines.begin(); entry != parsed_inlines.end(); ++ entry ) switch( entry->Type )
{
case CT_Preprocess_If:
case CT_Preprocess_IfDef:
{
b32 found = ignore_preprocess_cond_block(txt("GEN_INTELLISENSE_DIRECTIVES"), entry, parsed_inlines, inlines );
if (found) break;
found = ignore_preprocess_cond_block(txt("GEN_COMPILER_CPP"), entry, parsed_interface, interface);
if (found) break;
found = ignore_preprocess_cond_block(txt("0"), entry, parsed_interface, interface);
if (found) break;
inlines.append(entry);
}
break;
@ -1373,17 +1383,6 @@ R"(#define <interface_name>( code ) _Generic( (code), \
{
CodeFn fn = cast(CodeFn, entry);
Code prev = entry->Prev;
#if 0
for ( CodeParams arr_param : fn->Params )
{
b32 repeat_register_macros = fn->Name.is_equal(txt("register_macros")) && arr_param->Name.is_equal(txt("num")) && ! arr_param->Next->Name.is_equal(txt("..."));
if ( repeat_register_macros ) {
// rename second definition so there isn't a symbol conflict
StrBuilder postfix_arr = StrBuilder::fmt_buf(_ctx->Allocator_Temp, "%S_arr", fn->Name);
fn->Name = cache_str(postfix_arr.to_str());
}
}
#endif
src_interface.append(fn);
}
break;
@ -1450,18 +1449,6 @@ R"(#define <interface_name>( code ) _Generic( (code), \
{
CodeFn fn = cast(CodeFn, entry);
Code prev = entry->Prev;
#if 0
for ( CodeParams arr_param : fn->Params )
{
b32 repeat_def_array = fn->Name.starts_with(txt("def_")) && arr_param->Name.is_equal(txt("num")) && ! arr_param->Next->Name.is_equal(txt("..."));
if ( repeat_def_array ) {
// rename second definition so there isn't a symbol conflict
StrBuilder postfix_arr = StrBuilder::fmt_buf(_ctx->Allocator_Temp, "%S_arr", fn->Name);
fn->Name = cache_str(postfix_arr.to_str());
}
}
#endif
for ( CodeParams opt_param : fn->Params ) if (opt_param->ValueType->Name.starts_with(txt("Opts_")))
{
// The frontend names are warapped in macros so we need to give it the intenral symbol name

View File

@ -420,6 +420,8 @@ word make_code, gen_make_code
namespace set_allocator_, gen_set_allocator_
namespace Opts_, gen_Opts_
namespace def_, gen_def_
namespace parse_, gen_parse_
namespace token_, gen_token_

View File

@ -28,10 +28,9 @@ b32 ignore_preprocess_cond_block( Str cond_sig, Code& entry_iter, CodeBody& pars
//log_fmt("Preprocess cond found: %S\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) {
s32 depth = 0;
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:
@ -41,20 +40,18 @@ b32 ignore_preprocess_cond_block( Str cond_sig, Code& entry_iter, CodeBody& pars
case CT_Preprocess_Else:
++ entry_iter;
for(; continue_for && entry_iter != parsed_body.end(); ++ entry_iter)
if (depth == 1) for(; entry_iter != parsed_body.end(); ++ entry_iter)
{
if (entry_iter->Type == CT_Preprocess_EndIf)
{
continue_for = false;
if ( entry_iter->Type == CT_Preprocess_EndIf)
break;
}
body.append(entry_iter);
}
break;
case CT_Preprocess_EndIf:
{
depth --;
-- depth;
if (depth == 0) {
continue_for = false;
break;

View File

@ -8,11 +8,13 @@
# Segemented Library Generation
Create a segemented library using `segemented.cpp`
The principal (user) files are `gen.hpp` and `gen.cpp`.
They contain includes for its various components: `components/<component_name>.<hpp/cpp>`
Dependencies are bundled into `gen.dep.<hpp/cpp>`. They are included in `gen.<hpp/cpp>` before component includes.
Just like the `gen.<hpp/cpp>` they include their components: `dependencies/<dependency_name>.<hpp/cpp>`
Just like the `gen.<hpp/cpp>` they include their components: `dependencies/<dependency_name>.<hpp/cpp>`. The auxillary content (builder & scanner) is given their own files.
If using the library's provided build scripts:

View File

@ -2,7 +2,6 @@
#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"

View File

@ -1,6 +1,5 @@
#define GEN_DEFINE_LIBRARY_CODE_CONSTANTS
#define GEN_ENFORCE_STRONG_CODE_TYPES
#define GEN_EXPOSE_BACKEND
#include "gen.cpp"
#include "helpers/push_ignores.inline.hpp"

View File

@ -15,3 +15,20 @@ If using the library's provided build scripts:
```ps1
.\build.ps1 <compiler> <debug or omit> unreal
```
## Notables
For the most part this follows the same conventions as `gen_segmented`.
This generator uses a separate enumeration definitions for the following:
* [AttributeTokens.csv](./enums/AttributeTokens.csv) : Add your own <MODULE>_API attributes, etc here that are encountered within the Engine.
* [ESpecifier.csv](./enums/ESpecifier.csv) : Adds the `FORCEINLINE` & `FORCEINLINE_DEBUGGABLE` specfiers (additions are made as they are encountered)
* [ETokType.csv](./enums/ETokType.csv) : Same modifications as ESpecifier.csv.
A separate [parser_case_macros.cpp](./components/parser_case_macros.cpp) is used to accomodate for the new forceinline specifiers.
The `global` macro the library uses is redefined as an empty substiution.
The expected usage of this library is to put into into a third-party plugin module to then use either in editor modules or in shell script done in some stage of hot-reloading or building the Unreal Engine or Project.

View File

@ -1,6 +1,6 @@
// These macros are used in the swtich cases within parser.cpp
#define GEN_PARSER_CLASS_STRUCT_BODY_ALLOWED_MEMBER_TOK_SPECIFIERS_CASES \
#define GEN_PARSER_CLASS_STRUCT_BODY_ALLOWED_MEMBER_TOK_SPECIFIER_CASES \
case Tok_Spec_Consteval: \
case Tok_Spec_Constexpr: \
case Tok_Spec_Constinit: \
@ -14,7 +14,7 @@ case Tok_Spec_Static: \
case Tok_Spec_Volatile: \
case Tok_Spec_Virtual
#define GEN_PARSER_CLASS_STRUCT_BODY_ALLOWED_MEMBER_SPECIFIERS_CASES \
#define GEN_PARSER_CLASS_STRUCT_BODY_ALLOWED_MEMBER_SPECIFIER_CASES \
case Spec_Constexpr: \
case Spec_Constinit: \
case Spec_Explicit: \
@ -54,12 +54,12 @@ case Spec_NeverInline: \
case Spec_Static: \
case Spec_Volatile
#define GEN_PARSER_FRIEND_ALLOWED_SPECIFIERS_CASES \
#define GEN_PARSER_FRIEND_ALLOWED_SPECIFIER_CASES \
case Spec_Const: \
case Spec_Inline: \
case Spec_ForceInline
#define GEN_PARSER_FUNCTION_ALLOWED_SPECIFIERS_CASES \
#define GEN_PARSER_FUNCTION_ALLOWED_SPECIFIER_CASES \
case Spec_Const: \
case Spec_Consteval: \
case Spec_Constexpr: \
@ -71,7 +71,7 @@ case Spec_Inline: \
case Spec_NeverInline: \
case Spec_Static
#define GEN_PARSER_OPERATOR_ALLOWED_SPECIFIERS_CASES \
#define GEN_PARSER_OPERATOR_ALLOWED_SPECIFIER_CASES \
case Spec_Const: \
case Spec_Constexpr: \
case Spec_ForceInline: \
@ -79,7 +79,7 @@ case Spec_Inline: \
case Spec_NeverInline: \
case Spec_Static
#define GEN_PARSER_TEMPLATE_ALLOWED_SPECIFIERS_CASES \
#define GEN_PARSER_TEMPLATE_ALLOWED_SPECIFIER_CASES \
case Spec_Const: \
case Spec_Constexpr: \
case Spec_Constinit: \

View File

@ -13,8 +13,8 @@ BraceCurly_Open, "{"
BraceCurly_Close, "}"
BraceSquare_Open, "["
BraceSquare_Close, "]"
Capture_Start, "("
Capture_End, ")"
Paren_Open, "("
Paren_Close, ")"
Comment, "__comment__"
Comment_End, "__comment_end__"
Comment_Start, "__comment_start__"

1 Invalid __invalid__
13 BraceCurly_Close }
14 BraceSquare_Open [
15 BraceSquare_Close ]
16 Capture_Start Paren_Open (
17 Capture_End Paren_Close )
18 Comment __comment__
19 Comment_End __comment_end__
20 Comment_Start __comment_start__

View File

@ -1,6 +1,5 @@
#define GEN_DEFINE_LIBRARY_CODE_CONSTANTS
#define GEN_ENFORCE_STRONG_CODE_TYPES
#define GEN_EXPOSE_BACKEND
#include "gen.cpp"
#include "helpers/push_ignores.inline.hpp"

View File

@ -15,11 +15,13 @@ Its main uage is the [c_library generation](../gen_c_library/).
Remove any generated content from the repository.
**`build.ps1`**
Build c_library, segmented, singleheader, unreal. Supports msvc or clang, release or debug.
Build c library (segmented, singleheader, static, or dynamic), cpp library (segmented, singleheader, or unreal). Supports msvc or clang, release or debug.
```
```erlang
args:
c_library
c_lib : Build c11 library (singleheader & segmented)
c_lib_static : Build static c11 library
c_lib_dyn : Buidl dyanmic c11
segemented
singleheader
unreal

View File

@ -326,7 +326,7 @@ if ( $unreal )
}
# C Library testing
if ( $test -and $false )
if ( $test -and $true )
{
$path_test_c = join-path $path_test c_library
$path_build = join-path $path_test_c build

View File

@ -1,6 +1,5 @@
#define GEN_IMPLEMENTATION
#define GEN_DEFINE_LIBRARY_CODE_CONSTANTS
#define GEN_ENFORCE_STRONG_CODE_TYPES
#include "gen_singleheader.h"
#define gen_iterator( Type, container, iter ) \