27 Commits

Author SHA1 Message Date
Ed_
2c893d5e35 Merge pull request #34 from Ed94/dev
Dev
2023-09-07 23:06:02 -04:00
Ed_
6ea40094ee More fixes from clang warnings. Parser::lex prep for changes
parse_static_assert now properly adds new-line to end of statement.

I'm going to end up making a static_assert ast... that or when the statement ast is made it will handle adding that newline.
2023-09-07 22:52:51 -04:00
Ed_
0a8d3bfc6a Added fixed arenas (just ergonomics) 2023-09-07 22:29:04 -04:00
Ed_
212b4e6d16 Fixes for compiling with clang
Clang just had better errors and caught stuff msvc did not.
2023-09-07 21:11:57 -04:00
Ed_
d606c790ca Added a new AST member NextVar to be used for comma separated variable support.
Interface adding has been adjusted to use ParentType->Next.

Using the AST_Class->Next was bad since that breaks the linked list a body AST would have used for traversal.
2023-09-06 03:06:30 -04:00
Ed_
2bfbef1d0c strip_formatting : Remove code thats no longer needed.
Its everyting related to stripping a function body.
2023-09-06 02:09:26 -04:00
Ed_
f1fb75cc1c Progress on strip_formatting function, support for multi-dimentional array variables and typenames.
strip_formatting suffers from some edge failure with what looks to be escaped character literals (not entirely sure).

I've decided to not remove formatting from unvalidated function bodies since I plan to support parsing its content properly.
However expression values for a statement will fail to have their formatting removed with this.

Since I don't plan to parse those anytime soon, I'll have to fix any edge cases for those at least..
2023-09-06 02:07:09 -04:00
Ed_
2200bcde9a Improved singleheader test
Need to make the debug_str provided by the AST type aware to provide as much contextual information as possible (finally got to this point with validation).

Singleheader test now directly calls clang-format to cleanup the reconstructed copy of the singleheader. Its needed to remove any sort of formatting discrepancies found by the parser since its sensistive to that for new-lines, etc.
2023-09-05 13:36:59 -04:00
Ed_
3e249d9bc5 Reorganization of parser, refactor of parse_type( bool* ) and progression of parser docs
Wanted to make parser implementation easier to sift through, so I emphasized alphabetical order more.

Since I couldn't just strip whitespace from typenames I decided to make the parse_type more aware of the typename's components if it was a function signature.
This ofc lead to the dark & damp hell that is parsing typenames.

Also made initial implementation to support parsing decltype within a typename signature..

The test failure for the singleheader is still a thing, these changes have not addressed that.
2023-09-05 01:48:11 -04:00
Ed_
3868e1e811 Added cursed typedef 2023-09-04 12:32:31 -04:00
Ed_
543427dfe5 Fixes to parsing for validation
Removed whitespace stripping from parse_type, prepped for doing some major changes for function signature typenames

Moved template argument parsing to its own helper function since its used in more the one spot.

Latest failure is due to stack overflow when validating parameters. (Shouldn't be hard to debug)
2023-09-03 23:36:51 -04:00
Ed_
f2d4ec96f0 Dumb fix for name check on parameters
Its now spitting out actual validation failures.
2023-09-03 20:34:27 -04:00
Ed_
1076818250 Got whitepace stripping properly working (AFAICT) for parse_define()
Made debug for viewing whitespace in AST::is_equal with String::visualize_whitespace()

Format stripping code is currently confined within parse_define()

I plan to move it to its own function soon, I just want to make sure its finalized first.

Other unvalidated content will need to have an extra check for preprocessed lines.
Example: Function bodies can have a #define <identifier> <definition>. I cannot strip the last <new line> as it will break the semantic importance to distinguish that line.
So it needs to be:
<content before> <new line>
<preprocessed line> <new line>
<content after>

In the content string that is minimally preserved
2023-09-03 20:29:49 -04:00
Ed_
c4c308c8ba Fixes for auxilary code + typo fix in ast.cpp
Needed the intellisense directive ifdef wrap.
2023-08-29 00:03:08 -04:00
Ed_
a4d9a63d71 Updated single-header based on last cs and also docs 2023-08-28 23:52:44 -04:00
Ed_
0197afd543 Changed how editor intellisense directives are handled for compoenents and dependencies
Didn't like the way I was processing them in scan_file.
2023-08-28 23:46:50 -04:00
Ed_
7249a7317d Added space stripping during for content of various ASTs
* Typedef/Typename
* Function Names
* Pragmas
* Attributes
2023-08-26 11:55:05 -04:00
Ed_
abf51e4aa9 Adjustment to AST::is_equal based on issues found with last CS.
Defined check_member_content, will spit out the strings if they aren't equivalent so the user can verify for themselves if its correct.
2023-08-25 18:57:53 -04:00
Ed_
9b6dc3cbd8 Work on AST::is_equal.
The NumEntries checks need to be deferred until the end as a final unresolved check on valdiation. As if there really is a discrepancy of entires it should be revealed by the specific entry failing.

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

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

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

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

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

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

Those technically can be handled on a per-eye basis, and worst case the tests with the compiler will in the determine if any critical defintions are missing for the user.
2023-08-25 18:40:13 -04:00
Ed_
9edcbad907 Fixes to parsing marco content, progress on validation test (single-header) 2023-08-23 21:19:31 -04:00
Ed_
a6766cf0b1 Singleheader validation test got through ast reconstruction, failed to validate the reconstructed AST. 2023-08-23 18:16:45 -04:00
Ed_
8635b0fd1b doc update for parampack typename 2023-08-23 13:18:32 -04:00
Ed_
30eec99628 Changes to include usage, starting to attempt singleheader automated verification 2023-08-23 13:17:22 -04:00
Ed_
f9117a2353 Added zpl's ivrtual memory to dependencies (unused for now) 2023-08-23 11:07:43 -04:00
Ed_
c81f4b34ee Cleanup and doc updates 2023-08-23 02:17:47 -04:00
Ed_
c97762ac16 Added support for inline comments
Also now doing comment serialization on def_comment directly as parse_comment doesn't need it.

Essentially comment ast types serialize the same way s untyped and execution ASTs
2023-08-23 00:25:14 -04:00
Ed_
5e79e8ba65 Started to setup for codebase validation tests.
Fleshed out initial version of AST::is_equal( AST* )

Setup the test directory with initial files for each major validation test.
2023-08-22 16:01:50 -04:00
88 changed files with 4652 additions and 1856 deletions

6
.gitignore vendored
View File

@ -32,3 +32,9 @@ bld/
[Ll]og/
[Ll]ogs/
vc140.pdb
# Unreal
**/Unreal/*.h
**/Unreal/*.cpp
! **/Unreal/validate.unreal.cpp

View File

@ -10,8 +10,9 @@
"UNICODE",
"_UNICODE",
"GEN_TIME",
"GEN_IMPLEMENTATION"
"GEN_IMPLEMENTATION",
// "GEN_DONT_USE_NAMESPACE"
"GEN_INTELLISENSE_DIRECTIVES"
],
"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",
@ -28,8 +29,9 @@
"UNICODE",
"_UNICODE",
"GEN_TIME",
"GEN_IMPLEMENTATION"
"GEN_IMPLEMENTATION",
// "GEN_DONT_USE_NAMESPACE"
"GEN_INTELLISENSE_DIRECTIVES"
],
"windowsSdkVersion": "10.0.19041.0",
"compilerPath": "C:/Users/Ed/scoop/apps/llvm/current/bin/clang++.exe",

View File

@ -24,7 +24,11 @@
"filesystem": "cpp",
"format": "cpp",
"ratio": "cpp",
"xstring": "cpp"
"xstring": "cpp",
"functional": "cpp",
"vector": "cpp",
"list": "cpp",
"xhash": "cpp"
},
"C_Cpp.intelliSenseEngineFallback": "disabled",
"mesonbuild.configureOnOpen": true,

687
docs/ASTs.md Normal file
View File

@ -0,0 +1,687 @@
# ASTs Documentation
While the Readme for docs covers the data layout per AST, this will focus on the AST types avaialble, and their nuances.
## Body
These are containers representing a scope body of a definition that can be of the following `ECode` type:
* Class_Body
* Enum_Body
* Export_Body
* Extern_Linkage_Body
* Function_Body
* Global_Body
* Namespace_Body
* Struct_Body
* Union_Body
Fields:
```cpp
Code Front;
Code Back;
Code Parent;
StringCached Name;
CodeT Type;
s32 NumEntries;
```
The `Front` member represents the start of the link list and `Back` the end.
NumEntries is the number of entries in the body.
Parent should have a compatible ECode type for the type of defintion used.
Serialization:
Will output only the entries, the braces are handled by the parent.
```cpp
<Front>...
<Back>
```
## Attributes
Represent standard or vendor specific C/C++ attributes.
Fields:
```cpp
StringCached Content;
Code Prev;
Code Next;
Code Parent;
StringCached Name;
CodeT Type;
```
Serialization:
```cpp
<Content>
```
While the parser supports the `__declspec` and `__attribute__` syntax, the upfront constructor ( def_attributes ) must have the user specify the entire attribute, including the `[[]]`, `__declspec` or `__attribute__` parts.
## Comment
Stores a comment.
Fields:
```cpp
StringCached Content;
Code Prev;
Code Next;
Code Parent;
StringCached Name;
CodeT Type;
```
Serialization:
```cpp
<Content>
```
The parser will perserve comments found if residing with a body or in accepted inline-to-definition locations.
Otherwise they will be skipped by the TokArray::__eat and TokArray::current( skip foramtting enabled ) functions.
The upfront constructor: `def_comment` expects to recieve a comment without the `//` or `/* */` parts. It will add them during construction.
## Class & Struct
Fields:
```cpp
CodeComment InlineCmt; // Only supported by forward declarations
CodeAttributes Attributes;
CodeType ParentType;
CodeBody Body;
CodeType Last; // Used to store references to interfaces
CodeType Next; // Used to store references to interfaces
Code Parent;
StringCached Name;
CodeT Type;
ModuleFlag ModuleFlags;
AccessSpec ParentAccess;
```
Serialization:
```cpp
// Class_Fwd
<ModuleFlags> <class/struct> <Name>; <InlineCmt>
// Class
<ModuleFlags> <class/struct> <Attributes> <Name> : <ParentAccess> <ParentType>, public <Next>, ...<Last>
{
<Body>
};
```
You'll notice that only one parent type is supported only with parent access. This library only supports single inheritance, the rest must be done through interfaces.
## Constructor
Fields:
```cpp
CodeComment InlineCmt; // Only supported by forward declarations
Code InitializerList;
CodeParam Params;
Code Body;
Code Prev;
Code Next;
Code Parent;
CodeT Type;
```
Serialization:
```cpp
// Constructor_Fwd
<Specs> <Parent->Name>( <Params> ); <InlineCmt>
// Constructor
<Specs> <Parent->Name>( <Params> ): <InitializerList>
{
<Body>
}
```
## Define
Represents a preprocessor define
Fields:
```cpp
StringCached Content;
Code Prev;
Code Next;
Code Parent;
StringCached Name;
CodeT Type;
```
Serialization:
```cpp
#define <Name> <Content>
```
## Destructor
Fields:
```cpp
CodeComment InlineCmt;
CodeSpecifiers Specs;
Code Body;
Code Prev;
Code Next;
Code Parent;
CodeT Type;
```
Serialization:
```cpp
// Destructor_Fwd
<Specs> ~<Parent->Name>( <Params> ) <Specs>; <InlineCmt>
// Destructor
<Specs> ~<Parent->Name>( <Params> ) <Specs>
{
<Body>
}
```
## Enum
Fields:
```cpp
CodeComment InlineCmt;
CodeAttributes Attributes;
CodeType UnderlyingType;
CodeBody Body;
Code Prev;
Code Next;
Code Parent;
StringCached Name;
CodeT Type;
ModuleFlag ModuleFlags;
```
Serialization:
```cpp
// Enum_Fwd
<ModuleFlags> enum class <Name> : <UnderlyingType>; <InlineCmt>
// Enum
<ModuleFlags> <enum or enum class> <Name> : <UnderlyingType>
{
<Body>
};
```
## Execution
Just represents an execution body. Equivalent to an untyped body.
Will be obsolute when function body parsing is implemented.
Fields:
```cpp
StringCached Content;
Code Prev;
Code Next;
Code Parent;
StringCached Name;
CodeT Type;
```
Serialization:
```cpp
<Content>
```
## External Linkage
Fields:
```cpp
CodeBody Body;
Code Prev;
Code Next;
Code Parent;
StringCached Name;
CodeT Type;
```
Serialization:
```cpp
extern "<Name>"
{
<Body>
}
```
## Include
Fields:
```cpp
StringCached Content;
Code Prev;
Code Next;
Code Parent;
StringCached Name;
CodeT Type;
```
Serialization:
```cpp
#include <Content>
```
## Friend
This library (until its necessary become some third-party library to do otherwise) does not support friend declarations with in-statment function definitions.
Fields:
```cpp
CodeComment InlineCmt;
Code Declaration;
Code Prev;
Code Next;
Code Parent;
StringCached Name;
CodeT Type;
```
Serialization:
```cpp
friend <Declaration>; <InlineCmt>
```
## Function
Fields:
```cpp
CodeComment InlineCmt;
CodeAttributes Attributes;
CodeSpecifiers Specs;
CodeType ReturnType;
CodeParam Params;
CodeBody Body;
Code Prev;
Code Parent;
Code Next;
StringCached Name;
CodeT Type;
ModuleFlag ModuleFlags;
```
Serialization:
```cpp
// Function_Fwd
<ModuleFlags> <Attributes> <Specs> <ReturnType> <Name>( <Params> ) <Specs>; <InlineCmt>
// Function
<ModuleFlags> <Attributes> <Specs> <ReturnType> <Name>( <Params> ) <Specs>
{
<Body>
}
```
## Module
Fields:
```cpp
Code Prev;
Code Next;
Code Parent;
StringCached Name;
CodeT Type;
ModuleFlag ModuleFlags;
```
Serialization:
```cpp
<ModuleFlags> module <Name>;
```
## Namespace
Fields:
```cpp
CodeBody Body;
Code Prev;
Code Next;
Code Parent;
StringCached Name;
CodeT Type;
ModuleFlag ModuleFlags;
```
Serialization:
```cpp
<ModuleFlags> namespace <Name>
{
<Body>
}
```
## Operator Overload
Fields:
```cpp
CodeComment InlineCmt;
CodeAttributes Attributes;
CodeSpecifiers Specs;
CodeType ReturnType;
CodeParam Params;
CodeBody Body;
Code Prev;
Code Next;
Code Parent;
StringCached Name;
CodeT Type;
ModuleFlag ModuleFlags;
OperatorT Op;
```
Serialization:
```cpp
// Operator_Fwd
<ModuleFlags> <Attributes> <Specs> <ReturnType> operator <Op>( <Params> ) <Specs>; <InlineCmt>
// Operator
<ModuleFlags> <Attributes> <Specs> <ReturnType> <Name>operator <Op>( <Params> ) <Specs>
{
<Body>
}
```
## Operator Cast Overload ( User-Defined Type Conversion )
Fields:
```cpp
CodeComment InlineCmt;
CodeSpecifiers Specs;
CodeType ValueType;
CodeBody Body;
Code Prev;
Code Next;
Code Parent;
StringCached Name;
CodeT Type;
```
Serialization:
```cpp
// Operator_Cast_Fwd
<Specs> operator <ValueType>() <Specs>; <InlineCmt>
// Operator_Cast
<Specs> <Name>operator <ValueType>() <Specs>
{
<Body>
}
```
## Parameters
Fields:
```cpp
CodeType ValueType;
Code Value;
CodeParam Last;
CodeParam Next;
Code Parent;
StringCached Name;
CodeT Type;
s32 NumEntries;
```
Serialization:
```cpp
<ValueType> <Name>, <Next>... <Last>
```
## Pragma
Fields:
```cpp
StringCached Content;
Code Prev;
Code Next;
Code Parent;
StringCached Name;
CodeT Type;
```
Serialization:
```cpp
#pragma <Content>
```
## Preprocessor Conditional
Fields:
```cpp
StringCached Content;
Code Prev;
Code Next;
Code Parent;
StringCached Name;
CodeT Type;
```
Serialization:
```cpp
#<based off Type> <Content>
```
## Specifiers
Fields:
```cpp
SpecifierT ArrSpecs[ AST::ArrSpecs_Cap ];
Code Prev;
Code Next;
Code Parent;
StringCached Name;
CodeT Type;
s32 NumEntries;
```
Serialization:
```cpp
<Spec>, ...
```
## Template
Fields:
```cpp
CodeParam Params;
Code Declaration;
Code Prev;
Code Next;
Code Parent;
StringCached Name;
CodeT Type;
ModuleFlag ModuleFlags;
```
Serialization:
```cpp
<ModuleFlags>
template< <Params> >
<Declaration>
```
## Typename
Typenames represent the type "symbol".
Fields:
```cpp
CodeAttributes Attributes;
CodeSpecifiers Specs;
CodeReturnType ReturnType;
CodeParam Params;
Code ArrExpr;
Code Prev;
Code Next;
Code Parent;
StringCached Name;
CodeT Type;
b32 IsParamPack;
```
Serialization:
```cpp
<Attributes> <Name> <Specs> <IsParamPack ?: ...>
```
## Typedef
Behave as usual except function or macro typedefs.
Those don't use the underlying type field as everything was serialized under the Name field.
Fields:
```cpp
CodeComment InlineCmt;
Code UnderlyingType;
Code Prev;
Code Next;
Code Parent;
StringCached Name;
CodeT Type;
ModuleFlag ModuleFlags;
b32 IsFunction;
```
Serialization:
```cpp
// Regular
<ModuleFlags> typedef <UnderlyingType> <Name>; <InlineCmt>
// Functions
<ModuleFlags> typedef <Name>; <InlineCmt>
```
## Union
Fields:
```cpp
CodeAttributes Attributes;
CodeBody Body;
Code Prev;
Code Next;
Code Parent;
StringCached Name;
CodeT Type;
ModuleFlag ModuleFlags;
```
Serialization:
```cpp
<ModuleFlags> union <Attributes> <Name>
{
<Body>
}
```
## Using
Fields:
```cpp
CodeComment InlineCmt;
CodeAttributes Attributes;
CodeType UnderlyingType;
Code Prev;
Code Next;
Code Parent;
StringCached Name;
CodeT Type;
ModuleFlag ModuleFlags;
```
Serialization:
```cpp
// Regular
<ModuleFlags> using <Attributes> <Name> = <UnderlyingType>; <InlineCmt>
// Namespace
<ModuleFlags> using namespace <Name>; <InlineCmt>
```
## Variable
Fields:
```cpp
CodeComment InlineCmt;
CodeAttributes Attributes;
CodeSpecifiers Specs;
CodeType ValueType;
Code BitfieldSize;
Code Value;
Code Prev;
Code Next;
Code Parent;
StringCached Name;
CodeT Type;
ModuleFlag ModuleFlags;
```
Serialization:
```cpp
// Regular
<ModuleFlags> <Attributes> <Specs> <ValueType> <Name> = <Value>; <InlineCmt>
// Bitfield
<ModuleFlags> <Attributes> <Specs> <ValueType> <Name> : <BitfieldSize> = <Value>; <InlineCmt>
```

89
docs/Parser_Algo.md Normal file
View File

@ -0,0 +1,89 @@
# Parser's Algorithim
gencpp uses a hand-written recursive descent parser. Both the lexer and parser handle a full C/C++ file in a single pass.
## Notable implementation background
### Lexer
The lex procedure does the lexical pass of content provided as a `StrC` type.
The tokens are stored (for now) in `gen::Parser::Tokens`.
Fields:
```cpp
Array<Token> Arr;
s32 Idx;
```
What token types are supported can be found in [ETokType.csv](../project/enums/ETokType.csv) you can also find the token types in [ETokType.h](../project/components/gen/etoktype.cpp) , which is the generated enum from the csv file.
Tokens are defined with the struct `gen::Parser::Token`:
Fields:
```cpp
char const* Text;
sptr Length;
TokType Type;
s32 Line;
s32 Column;
bool IsAssign;
```
`IsAssign` is a flag that is set when the token is an assignment operator. Which is used for various purposes:
* Using statment assignment
* Parameter argument default value assignment
* Variable declaration initialization assignment
I plan to replace IsAssign with a general flags field and properly keep track of all operator types instead of abstracting it away to `ETokType::Operator`.
Traversing the tokens is done with the following interface macros:
| Macro | Description |
| --- | --- |
| `currtok_noskip` | Get the current token without skipping whitespace |
| `currtok` | Get the current token, skip any whitespace tokens |
| `prevtok` | Get the previous token (does not skip whitespace) |
| `nexttok` | Get the next token (does not skip whitespace) |
| `eat( Token Type )` | Check to see if the current token is of the given type, if so, advance Token's index to the next token |
| `left` | Get the number of tokens left in the token array |
| `check_noskip` | Check to see if the current token is of the given type, without skipping whitespace |
| `check` | Check to see if the current token is of the given type, skip any whitespace tokens |
### Parser
The parser has a limited user interface, only specific types of definitions or statements are expected to be provided by the user directly when using to construct an AST dynamically (See SOA for example). It however does attempt to provide capability to parse a full C/C++ from production codebases.
Each public user interface procedure has the following format:
```cpp
CodeStruct parse_<definition type>( StrC def )
{
check_parse_args( def );
using namespace Parser;
TokArray toks = lex( def );
if ( toks.Arr == nullptr )
return CodeInvalid;
// Parse the tokens and return a constructed AST using internal procedures
...
}
```
The most top-level parsing procedure used for C/C++ file parsing is `parse_global_body`:
It uses a helper procedure called `parse_global_nspace`.
Each internal procedure will be
## parse_global_nspace
1. Make sure the type provided to the helper function is a `Namespace_Body`, `Global_Body`, `Export_Body`, `Extern_Linkage_body`.
2. If its not a `Global_Body` eat the opening brace for the scope.
3.
## parse_type

View File

@ -1,9 +1,12 @@
# Parsing
The library features a naive parser tailored for only what the library needs to construct the supported syntax of C++ into its AST.
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) under 5000 loc.
The library features a naive parser tailored for only what the library needs to construct the supported syntax of C++ into its AST.
The parsing implementation supports the following for the user:
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 5000 loc.
You can think of this parser of a 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.
User exposed interface:
```cpp
CodeClass parse_class ( StrC class_def );
@ -27,10 +30,12 @@ CodeUsing parse_using ( StrC using_def );
CodeVar parse_variable ( StrC var_def );
```
To parse file buffers, use the `parse_global_body` function.
***Parsing will aggregate any tokens within a function body or expression statement to an untyped Code AST.***
Everything is done in one pass for both the preprocessor directives and the rest of the language.
The parser performs no macro expansion as the scope of gencpp feature-set is to only support the preprocessor for the goal of having rudimentary awareness of preprocessor ***conditionals***, ***defines***, and ***includes***, and ***pragmas***.
The parser performs no macro expansion as the scope of gencpp feature-set is to only support the preprocessor for the goal of having rudimentary awareness of preprocessor ***conditionals***, ***defines***, ***includes***, and ***pragmas***.
The keywords supported for the preprocessor are:
@ -51,10 +56,17 @@ Any preprocessor definition abuse that changes the syntax of the core language i
Exceptions:
* function signatures 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`
*(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.*
The lexing and parsing takes shortcuts from whats expected in the standard.
* Numeric literals are not checked for validity.
@ -64,8 +76,7 @@ The lexing and parsing takes shortcuts from whats expected in the standard.
* Assumed to *come before specifiers* (`const`, `constexpr`, `extern`, `static`, etc) for a function
* Or in the usual spot for class, structs, (*right after the declaration keyword*)
* typedefs have attributes with the type (`parse_type`)
* As a general rule; if its not available from the upfront constructors, its not available in the parsing constructors.
* *Upfront constructors are not necessarily used in the parsing constructors, this is just a good metric to know what can be parsed.*
* Parsing attributes can be extended to support user defined macros by defining `GEN_DEFINE_ATTRIBUTE_TOKENS` (see `gen.hpp` for the formatting)
Empty lines used throughout the file are preserved for formatting purposes during ast serialization.

View File

@ -40,6 +40,7 @@
</AdditionalIncludePaths>
<Defines>
<Define>GEN_TIME</Define>
<Define>GEN_SYSTEM_WINDOWS</Define>
</Defines>
<ConfigProperties>
<ConfigAndPlatform>

View File

@ -1,4 +1,6 @@
#include "builder.hpp"
#ifdef GEN_INTELLISENSE_DIRECTIVES
# include "builder.hpp"
#endif
Builder Builder::open( char const* path )
{
@ -26,8 +28,7 @@ void Builder::pad_lines( s32 num )
void Builder::print( Code code )
{
String str = code->to_string();
const sw len = str.length();
// const sw len = str.length();
// log_fmt( "%s - print: %.*s\n", File.filename, len > 80 ? 80 : len, str.Data );
Buffer.append( str );
}

View File

@ -1,5 +1,7 @@
#pragma once
#include "gen.hpp"
#ifdef GEN_INTELLISENSE_DIRECTIVES
# pragma once
# include "gen.hpp"
#endif
struct Builder
{

View File

@ -1,67 +0,0 @@
#pragma once
#include "gen.scanner.hpp"
struct Policy
{
// Nothing for now.
};
enum class SymbolType : u32
{
Code,
Line,
Marker
};
struct Editor
{
enum RequestType : u32
{
Add,
Replace,
Remove
};
struct SymbolData
{
Policy Policy;
SymbolInfo Info;
};
struct RequestEntry
{
union {
SymbolData Symbol;
String Specification;
};
RequestType Type;
};
struct Receipt
{
StringCached File;
Code Found;
Code Written;
bool Result;
};
static AllocatorInfo Allocator;
static void set_allocator( AllocatorInfo allocator );
Array<FileInfo> Files;
String Buffer;
Array<RequestEntry> Requests;
void add_files( s32 num, char const** files );
void add ( SymbolInfo definition, Policy policy, Code to_inject );
void remove ( SymbolInfo definition, Policy policy );
void replace( SymbolInfo definition, Policy policy, Code to_replace);
# ifdef GEN_FEATURE_EDITOR_REFACTOR
void refactor( char const* file_path, char const* specification_path );
# endif
bool process_requests( Array<Receipt> out_receipts );
};

View File

@ -1,10 +1,12 @@
#pragma once
#include "gen.hpp"
#ifdef GEN_INTELLISENSE_DIRECTIVES
# pragma once
# include "gen.hpp"
#endif
// This is a simple file reader that reads the entire file into memory.
// It has an extra option to skip the first few lines for undesired includes.
// This is done so that includes can be kept in dependency and component files so that intellisense works.
Code scan_file( char const* path, bool skip_initial_directives = true )
Code scan_file( char const* path )
{
FileInfo file;
@ -24,63 +26,92 @@ Code scan_file( char const* path, bool skip_initial_directives = true )
file_read( & file, str, fsize );
str.get_header().Length = fsize;
if ( skip_initial_directives )
// Skip GEN_INTELLISENSE_DIRECTIVES preprocessor blocks
// Its designed so that the directive should be the first thing in the file.
// Anything that comes before it will also be omitted.
{
#define current (*scanner)
StrC toks[] {
txt( "pragma once" ),
txt( "include" )
};
#define matched 0
#define move_fwd() do { ++ scanner; -- left; } while (0)
const StrC directive_start = txt( "ifdef" );
const StrC directive_end = txt( "endif" );
const StrC def_intellisense = txt("GEN_INTELLISENSE_DIRECTIVES" );
char* scanner = str;
while ( current != '\r' && current != '\n' )
bool found_directive = false;
char const* scanner = str.Data;
s32 left = fsize;
while ( left )
{
for ( StrC tok : toks )
// Processing directive.
if ( current == '#' )
{
if ( current == '#' )
{
++ scanner;
}
move_fwd();
while ( left && char_is_space( current ) )
move_fwd();
if ( strncmp( scanner, tok.Ptr, tok.Len ) == 0 )
if ( ! found_directive )
{
scanner += tok.Len;
while ( scanner < ( str.Data + str.length() ) && current != '\r' && current != '\n' )
if ( left && str_compare( scanner, directive_start.Ptr, directive_start.Len ) == matched )
{
++ scanner;
scanner += directive_start.Len;
left -= directive_start.Len;
while ( left && char_is_space( current ) )
move_fwd();
if ( left && str_compare( scanner, def_intellisense.Ptr, def_intellisense.Len ) == matched )
{
scanner += def_intellisense.Len;
left -= def_intellisense.Len;
found_directive = true;
}
}
// Skip the line
sptr skip_size = sptr( scanner - str.Data );
if ( (scanner + 2) >= ( str.Data + str.length() ) )
// Skip to end of line
while ( left && current != '\r' && current != '\n' )
move_fwd();
move_fwd();
if ( left && current == '\n' )
move_fwd();
continue;
}
if ( left && str_compare( scanner, directive_end.Ptr, directive_end.Len ) == matched )
{
scanner += directive_end.Len;
left -= directive_end.Len;
// Skip to end of line
while ( left && current != '\r' && current != '\n' )
move_fwd();
move_fwd();
if ( left && current == '\n' )
move_fwd();
// sptr skip_size = fsize - left;
if ( (scanner + 2) >= ( str.Data + fsize ) )
{
sptr new_length = sptr( str.get_header().Length ) - skip_size;
mem_move( str, scanner, new_length );
str.get_header().Length = new_length;
mem_move( str, scanner, left );
str.get_header().Length = left;
break;
}
if ( current == '\r' )
{
skip_size += 2;
scanner += 2;
}
else
{
skip_size += 1;
scanner += 1;
}
mem_move( str, scanner, left );
str.get_header().Length = left;
sptr new_length = sptr( str.get_header().Length ) - skip_size;
mem_move( str, scanner, new_length );
str.get_header().Length = new_length;
scanner = str;
break;
}
}
++ scanner;
move_fwd();
}
#undef move_fwd
#undef matched
#undef current
}

View File

@ -17,21 +17,19 @@ GEN_NS_END
using namespace gen;
constexpr char const* generation_notice =
"// This file was generated automatially by gen.bootstrap.cpp "
"// This file was generated automatially by gencpp's bootstrap.cpp "
"(See: https://github.com/Ed94/gencpp)\n\n";
constexpr bool DontSkipInitialDirectives = false;
int gen_main()
{
gen::init();
Code push_ignores = scan_file( "helpers/push_ignores.inline.hpp", DontSkipInitialDirectives );
Code pop_ignores = scan_file( "helpers/pop_ignores.inline.hpp", DontSkipInitialDirectives );
Code push_ignores = scan_file( "helpers/push_ignores.inline.hpp" );
Code pop_ignores = scan_file( "helpers/pop_ignores.inline.hpp" );
// gen_dep.hpp
{
Code header_start = scan_file( "dependencies/header_start.hpp", DontSkipInitialDirectives );
Code header_start = scan_file( "dependencies/header_start.hpp" );
Code macros = scan_file( "dependencies/macros.hpp" );
Code basic_types = scan_file( "dependencies/basic_types.hpp" );
Code debug = scan_file( "dependencies/debug.hpp" );
@ -147,31 +145,35 @@ int gen_main()
header.print( pop_ignores );
header.write();
CodeBody gen_component_header = def_global_body( args(
def_preprocess_cond( PreprocessCond_IfDef, txt("GEN_INTELLISENSE_DIRECTIVES") ),
pragma_once,
preprocess_endif,
fmt_newline,
untyped_str( to_str(generation_notice) )
));
Builder
header_ecode = Builder::open( "components/gen/ecode.hpp" );
header_ecode.print( pragma_once );
header_ecode.print_fmt( generation_notice );
header_ecode.print( gen_component_header );
header_ecode.print( ecode );
header_ecode.write();
Builder
header_eoperator = Builder::open( "components/gen/eoperator.hpp" );
header_eoperator.print( pragma_once );
header_eoperator.print_fmt( generation_notice );
header_eoperator.print( gen_component_header );
header_eoperator.print( eoperator );
header_eoperator.write();
Builder
header_especifier = Builder::open( "components/gen/especifier.hpp" );
header_especifier.print( pragma_once );
header_especifier.print_fmt( generation_notice );
header_especifier.print( gen_component_header );
header_especifier.print( especifier );
header_especifier.write();
Builder
header_ast_inlines = Builder::open( "components/gen/ast_inlines.hpp" );
header_ast_inlines.print( pragma_once );
header_ast_inlines.print_fmt( generation_notice );
header_ast_inlines.print( gen_component_header );
header_ast_inlines.print( ast_inlines );
header_ast_inlines.write();
}

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,10 @@
#ifdef GEN_INTELLISENSE_DIRECTIVES
#pragma once
#include "types.hpp"
#include "gen/ecode.hpp"
#include "gen/eoperator.hpp"
#include "gen/especifier.hpp"
#endif
struct AST;
struct AST_Body;
@ -80,7 +82,7 @@ struct Code
static Code Invalid;
# pragma endregion Statics
#define Using_Code( Typename ) \
# define Using_Code( Typename ) \
char const* debug_str(); \
Code duplicate(); \
bool is_equal( Code other ); \
@ -220,33 +222,39 @@ struct AST
- sizeof(CodeT)
- sizeof(ModuleFlag)
- sizeof(u32)
- sizeof(s32)
)
/ sizeof(SpecifierT) - 1; // -1 for 4 extra bytes
union {
struct
{
AST* Attributes; // Class, Enum, Function, Struct, Typedef, Union, Using, Variable
AST* Specs; // Function, Operator, Type symbol, Variable
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, Destructor
AST* ParentType; // Class, Struct
AST* ReturnType; // Function, Operator
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* BitfieldSize; // Varaiable (Class/Struct Data Member)
AST* Params; // Function, Operator, Template
AST* BitfieldSize; // Variable (Class/Struct Data Member)
AST* Params; // Constructor, Function, Operator, Template, Typename
};
union {
AST* ArrExpr; // Type Symbol
AST* Body; // Class, Constructr, Destructor, Enum, Function, Namespace, Struct, Union
AST* Declaration; // Friend, Template
AST* Value; // Parameter, Variable
AST* ArrExpr; // Typename
AST* Body; // Class, Constructr, Destructor, Enum, 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* SpecsFuncSuffix; // Only used with typenames, to store the function suffix if typename is function signature.
};
};
StringCached Content; // Attributes, Comment, Execution, Include
StringCached Content; // Attributes, Comment, Execution, Include
SpecifierT ArrSpecs[AST::ArrSpecs_Cap]; // Specifiers
};
union {
@ -263,11 +271,13 @@ struct AST
CodeT Type;
ModuleFlag ModuleFlags;
union {
b32 IsFunction; // Used by typedef to not serialize the name field.
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 Token; // Handle to the token, stored in the CodeFile (Otherwise unretrivable)
};
struct AST_POD
@ -275,27 +285,32 @@ struct AST_POD
union {
struct
{
AST* Attributes; // Class, Enum, Function, Struct, Typename, Union, Using, Variable
AST* Specs; // Function, Operator, Type symbol, Variable
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, Destructor
AST* ParentType; // Class, Struct
AST* ReturnType; // Function, Operator
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* BitfieldSize; // Varaiable (Class/Struct Data Member)
AST* Params; // Function, Operator, Template
AST* BitfieldSize; // Variable (Class/Struct Data Member)
AST* Params; // Constructor, Function, Operator, Template, Typename
};
union {
AST* ArrExpr; // Type Symbol
AST* Body; // Class, Constructr, Destructor, Enum, Function, Namespace, Struct, Union
AST* Declaration; // Friend, Template
AST* Value; // Parameter, Variable
AST* ArrExpr; // Typename
AST* Body; // Class, Constructr, Destructor, Enum, 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* SpecsFuncSuffix; // Only used with typenames, to store the function suffix if typename is function signature.
};
};
StringCached Content; // Attributes, Comment, Execution, Include
StringCached Content; // Attributes, Comment, Execution, Include
SpecifierT ArrSpecs[AST::ArrSpecs_Cap]; // Specifiers
};
union {
@ -312,11 +327,13 @@ struct AST_POD
CodeT Type;
ModuleFlag ModuleFlags;
union {
b32 IsFunction; // Used by typedef to not serialize the name field.
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 Token; // Handle to the token, stored in the CodeFile (Otherwise unretrivable)
};
// Its intended for the AST to have equivalent size to its POD.

View File

@ -1,5 +1,7 @@
#pragma once
#include "ast.hpp"
#ifdef GEN_INTELLISENSE_DIRECTIVES
# pragma once
# include "ast.hpp"
#endif
#pragma region AST Types
/*
@ -18,6 +20,7 @@ struct AST_Body
CodeT Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) ];
s32 NumEntries;
s32 Token;
};
static_assert( sizeof(AST_Body) == sizeof(AST), "ERROR: AST_Filtered is not the same size as AST");
@ -33,6 +36,7 @@ struct AST_Attributes
StringCached Name;
CodeT Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ];
s32 Token;
};
static_assert( sizeof(AST_Attributes) == sizeof(AST), "ERROR: AST_Attributes is not the same size as AST");
@ -48,6 +52,7 @@ struct AST_Comment
StringCached Name;
CodeT Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ];
s32 Token;
};
static_assert( sizeof(AST_Comment) == sizeof(AST), "ERROR: AST_Comment is not the same size as AST");
@ -57,11 +62,13 @@ struct AST_Class
char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap ];
struct
{
CodeComment InlineCmt; // Only supported by forward declarations
CodeAttributes Attributes;
char _PAD_SPECS_ [ sizeof(AST*) ];
CodeType ParentType;
char _PAD_PARAMS_[ sizeof(AST*) ];
CodeBody Body;
char _PAD_PROPERTIES_2_[ sizeof(AST*) ];
};
};
CodeType Last;
@ -71,6 +78,7 @@ struct AST_Class
CodeT Type;
ModuleFlag ModuleFlags;
AccessSpec ParentAccess;
s32 Token;
};
static_assert( sizeof(AST_Class) == sizeof(AST), "ERROR: AST_Class is not the same size as AST");
@ -80,18 +88,22 @@ struct AST_Constructor
char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap ];
struct
{
char _PAD_PROPERTIES_ [ sizeof(AST*) * 3 ];
Code InitializerList;
CodeParam Params;
Code Body;
CodeComment InlineCmt; // Only supported by forward declarations
char _PAD_PROPERTIES_ [ sizeof(AST*) * 1 ];
CodeSpecifiers Specs;
Code InitializerList;
CodeParam Params;
Code Body;
char _PAD_PROPERTIES_2_ [ sizeof(AST*) * 2 ];
};
};
Code Prev;
Code Next;
Code Parent;
StringCached Name;
char _PAD_NAME_[ sizeof(StringCached) ];
CodeT Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ];
char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ];
s32 Token;
};
static_assert( sizeof(AST_Constructor) == sizeof(AST), "ERROR: AST_Constructor is not the same size as AST");
@ -107,6 +119,7 @@ struct AST_Define
StringCached Name;
CodeT Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ];
s32 Token;
};
static_assert( sizeof(AST_Define) == sizeof(AST), "ERROR: AST_Define is not the same size as AST");
@ -116,18 +129,21 @@ struct AST_Destructor
char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap ];
struct
{
CodeComment InlineCmt;
char _PAD_PROPERTIES_ [ sizeof(AST*) * 1 ];
CodeSpecifiers Specs;
char _PAD_PROPERTIES_2_ [ sizeof(AST*) * 2 ];
Code Body;
char _PAD_PROPERTIES_3_ [ sizeof(AST*) ];
};
};
Code Prev;
Code Next;
Code Parent;
StringCached Name;
char _PAD_NAME_[ sizeof(StringCached) ];
CodeT Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ];
s32 Token;
};
static_assert( sizeof(AST_Destructor) == sizeof(AST), "ERROR: AST_Destructor is not the same size as AST");
@ -137,11 +153,13 @@ struct AST_Enum
char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap ];
struct
{
CodeComment InlineCmt;
CodeAttributes Attributes;
char _PAD_SPEC_ [ sizeof(AST*) ];
CodeType UnderlyingType;
char _PAD_PARAMS_[ sizeof(AST*) ];
CodeBody Body;
char _PAD_PROPERTIES_2_[ sizeof(AST*) ];
};
};
Code Prev;
@ -151,6 +169,7 @@ struct AST_Enum
CodeT Type;
ModuleFlag ModuleFlags;
char _PAD_UNUSED_[ sizeof(u32) ];
s32 Token;
};
static_assert( sizeof(AST_Enum) == sizeof(AST), "ERROR: AST_Enum is not the same size as AST");
@ -158,10 +177,7 @@ struct AST_Exec
{
union {
char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap ];
struct
{
char _PAD_PROPERTIES_[ sizeof(AST*) * 5 ];
};
StringCached Content;
};
Code Prev;
Code Next;
@ -169,6 +185,7 @@ struct AST_Exec
StringCached Name;
CodeT Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ];
s32 Token;
};
static_assert( sizeof(AST_Exec) == sizeof(AST), "ERROR: AST_Exec is not the same size as AST");
@ -178,8 +195,9 @@ struct AST_Extern
char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap ];
struct
{
char _PAD_PROPERTIES_[ sizeof(AST*) * 4 ];
char _PAD_PROPERTIES_[ sizeof(AST*) * 5 ];
CodeBody Body;
char _PAD_PROPERTIES_2_[ sizeof(AST*) ];
};
};
Code Prev;
@ -188,6 +206,7 @@ struct AST_Extern
StringCached Name;
CodeT Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ];
s32 Token;
};
static_assert( sizeof(AST_Extern) == sizeof(AST), "ERROR: AST_Extern is not the same size as AST");
@ -203,6 +222,7 @@ struct AST_Include
StringCached Name;
CodeT Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ];
s32 Token;
};
static_assert( sizeof(AST_Include) == sizeof(AST), "ERROR: AST_Include is not the same size as AST");
@ -212,8 +232,10 @@ struct AST_Friend
char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap ];
struct
{
char _PAD_PROPERTIES_[ sizeof(AST*) * 4 ];
Code Declaration;
CodeComment InlineCmt;
char _PAD_PROPERTIES_[ sizeof(AST*) * 4 ];
Code Declaration;
char _PAD_PROPERTIES_2_[ sizeof(AST*) ];
};
};
Code Prev;
@ -222,6 +244,7 @@ struct AST_Friend
StringCached Name;
CodeT Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ];
s32 Token;
};
static_assert( sizeof(AST_Friend) == sizeof(AST), "ERROR: AST_Friend is not the same size as AST");
@ -231,11 +254,13 @@ struct AST_Fn
char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap ];
struct
{
CodeComment InlineCmt;
CodeAttributes Attributes;
CodeSpecifiers Specs;
CodeType ReturnType;
CodeParam Params;
CodeBody Body;
char _PAD_PROPERTIES_ [ sizeof(AST*) ];
};
};
Code Prev;
@ -245,6 +270,7 @@ struct AST_Fn
CodeT Type;
ModuleFlag ModuleFlags;
char _PAD_UNUSED_[ sizeof(u32) ];
s32 Token;
};
static_assert( sizeof(AST_Fn) == sizeof(AST), "ERROR: AST_Fn is not the same size as AST");
@ -258,6 +284,7 @@ struct AST_Module
CodeT Type;
ModuleFlag ModuleFlags;
char _PAD_UNUSED_[ sizeof(u32) ];
s32 Token;
};
static_assert( sizeof(AST_Module) == sizeof(AST), "ERROR: AST_Module is not the same size as AST");
@ -266,8 +293,9 @@ struct AST_NS
union {
char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap ];
struct {
char _PAD_PROPERTIES_[ sizeof(AST*) * 4 ];
char _PAD_PROPERTIES_[ sizeof(AST*) * 5 ];
CodeBody Body;
char _PAD_PROPERTIES_2_[ sizeof(AST*) ];
};
};
Code Prev;
@ -277,6 +305,7 @@ struct AST_NS
CodeT Type;
ModuleFlag ModuleFlags;
char _PAD_UNUSED_[ sizeof(u32) ];
s32 Token;
};
static_assert( sizeof(AST_NS) == sizeof(AST), "ERROR: AST_NS is not the same size as AST");
@ -286,11 +315,13 @@ struct AST_Operator
char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap ];
struct
{
CodeComment InlineCmt;
CodeAttributes Attributes;
CodeSpecifiers Specs;
CodeType ReturnType;
CodeParam Params;
CodeBody Body;
char _PAD_PROPERTIES_ [ sizeof(AST*) ];
};
};
Code Prev;
@ -300,6 +331,7 @@ struct AST_Operator
CodeT Type;
ModuleFlag ModuleFlags;
OperatorT Op;
s32 Token;
};
static_assert( sizeof(AST_Operator) == sizeof(AST), "ERROR: AST_Operator is not the same size as AST");
@ -309,11 +341,13 @@ struct AST_OpCast
char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap ];
struct
{
CodeComment InlineCmt;
char _PAD_PROPERTIES_[ sizeof(AST*) ];
CodeSpecifiers Specs;
CodeType ValueType;
char _PAD_PROPERTIES_2_[ sizeof(AST*) ];
CodeBody Body;
char _PAD_PROPERTIES_3_[ sizeof(AST*) ];
};
};
Code Prev;
@ -322,6 +356,7 @@ struct AST_OpCast
StringCached Name;
CodeT Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ];
s32 Token;
};
static_assert( sizeof(AST_OpCast) == sizeof(AST), "ERROR: AST_OpCast is not the same size as AST");
@ -331,10 +366,11 @@ struct AST_Param
char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap ];
struct
{
char _PAD_PROPERTIES_2_[ sizeof(AST*) * 2 ];
char _PAD_PROPERTIES_2_[ sizeof(AST*) * 3 ];
CodeType ValueType;
char _PAD_PROPERTIES_[ sizeof(AST*) ];
Code Value;
char _PAD_PROPERTIES_3_[ sizeof(AST*) ];
};
};
CodeParam Last;
@ -344,6 +380,7 @@ struct AST_Param
CodeT Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) ];
s32 NumEntries;
s32 Token;
};
static_assert( sizeof(AST_Param) == sizeof(AST), "ERROR: AST_Param is not the same size as AST");
@ -359,6 +396,7 @@ struct AST_Pragma
StringCached Name;
CodeT Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ];
s32 Token;
};
static_assert( sizeof(AST_Pragma) == sizeof(AST), "ERROR: AST_Pragma is not the same size as AST");
@ -374,6 +412,7 @@ struct AST_PreprocessCond
StringCached Name;
CodeT Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ];
s32 Token;
};
static_assert( sizeof(AST_PreprocessCond) == sizeof(AST), "ERROR: AST_PreprocessCond is not the same size as AST");
@ -387,6 +426,7 @@ struct AST_Specifiers
CodeT Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) ];
s32 NumEntries;
s32 Token;
};
static_assert( sizeof(AST_Specifiers) == sizeof(AST), "ERROR: AST_Specifier is not the same size as AST");
@ -396,11 +436,13 @@ struct AST_Struct
char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap ];
struct
{
CodeComment InlineCmt;
CodeAttributes Attributes;
char _PAD_SPECS_ [ sizeof(AST*) ];
CodeType ParentType;
char _PAD_PARAMS_[ sizeof(AST*) ];
CodeBody Body;
char _PAD_PROPERTIES_2_[ sizeof(AST*) ];
};
};
CodeType Last;
@ -410,6 +452,7 @@ struct AST_Struct
CodeT Type;
ModuleFlag ModuleFlags;
AccessSpec ParentAccess;
s32 Token;
};
static_assert( sizeof(AST_Struct) == sizeof(AST), "ERROR: AST_Struct is not the same size as AST");
@ -419,9 +462,10 @@ struct AST_Template
char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap ];
struct
{
char _PAD_PROPERTIES_[ sizeof(AST*) * 3 ];
char _PAD_PROPERTIES_[ sizeof(AST*) * 4 ];
CodeParam Params;
Code Declaration;
char _PAD_PROPERTIES_2_[ sizeof(AST*) ];
};
};
Code Prev;
@ -431,6 +475,7 @@ struct AST_Template
CodeT Type;
ModuleFlag ModuleFlags;
char _PAD_UNUSED_[ sizeof(u32) ];
s32 Token;
};
static_assert( sizeof(AST_Template) == sizeof(AST), "ERROR: AST_Template is not the same size as AST");
@ -440,10 +485,13 @@ struct AST_Type
char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap ];
struct
{
char _PAD_INLINE_CMT_[ sizeof(AST*) ];
CodeAttributes Attributes;
CodeSpecifiers Specs;
char _PAD_PROPERTIES_[ sizeof(AST*) * 2 ];
CodeType ReturnType; // Only used for function signatures
CodeParam Params; // Only used for function signatures
Code ArrExpr;
CodeSpecifiers SpecsFuncSuffix; // Only used for function signatures
};
};
Code Prev;
@ -451,7 +499,9 @@ struct AST_Type
Code Parent;
StringCached Name;
CodeT Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ];
char _PAD_UNUSED_[ sizeof(ModuleFlag) ];
b32 IsParamPack;
s32 Token;
};
static_assert( sizeof(AST_Type) == sizeof(AST), "ERROR: AST_Type is not the same size as AST");
@ -461,9 +511,10 @@ struct AST_Typedef
char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap ];
struct
{
CodeComment InlineCmt;
char _PAD_PROPERTIES_[ sizeof(AST*) * 2 ];
Code UnderlyingType;
char _PAD_PROPERTIES_2_[ sizeof(AST*) * 2 ];
char _PAD_PROPERTIES_2_[ sizeof(AST*) * 3 ];
};
};
Code Prev;
@ -473,6 +524,7 @@ struct AST_Typedef
CodeT Type;
ModuleFlag ModuleFlags;
b32 IsFunction;
s32 Token;
};
static_assert( sizeof(AST_Typedef) == sizeof(AST), "ERROR: AST_Typedef is not the same size as AST");
@ -482,9 +534,11 @@ struct AST_Union
char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap ];
struct
{
char _PAD_INLINE_CMT_[ sizeof(AST*) ];
CodeAttributes Attributes;
char _PAD_PROPERTIES_[ sizeof(AST*) * 3 ];
CodeBody Body;
char _PAD_PROPERTIES_2_[ sizeof(AST*) ];
};
};
Code Prev;
@ -494,6 +548,7 @@ struct AST_Union
CodeT Type;
ModuleFlag ModuleFlags;
char _PAD_UNUSED_[ sizeof(u32) ];
s32 Token;
};
static_assert( sizeof(AST_Union) == sizeof(AST), "ERROR: AST_Union is not the same size as AST");
@ -503,10 +558,11 @@ struct AST_Using
char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap ];
struct
{
CodeComment InlineCmt;
CodeAttributes Attributes;
char _PAD_SPECS_ [ sizeof(AST*) ];
CodeType UnderlyingType;
char _PAD_PROPERTIES_[ sizeof(AST*) * 2 ];
char _PAD_PROPERTIES_[ sizeof(AST*) * 3 ];
};
};
Code Prev;
@ -516,6 +572,7 @@ struct AST_Using
CodeT Type;
ModuleFlag ModuleFlags;
char _PAD_UNUSED_[ sizeof(u32) ];
s32 Token;
};
static_assert( sizeof(AST_Using) == sizeof(AST), "ERROR: AST_Using is not the same size as AST");
@ -525,11 +582,13 @@ struct AST_Var
char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap ];
struct
{
CodeComment InlineCmt;
CodeAttributes Attributes;
CodeSpecifiers Specs;
CodeType ValueType;
Code BitfieldSize;
Code Value;
CodeVar NextVar;
};
};
Code Prev;
@ -539,6 +598,7 @@ struct AST_Var
CodeT Type;
ModuleFlag ModuleFlags;
char _PAD_UNUSED_[ sizeof(u32) ];
s32 Token;
};
static_assert( sizeof(AST_Var) == sizeof(AST), "ERROR: AST_Var is not the same size as AST");

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,8 @@
#ifdef GEN_INTELLISENSE_DIRECTIVES
#pragma once
#endif
// This file was generated automatially by gen.bootstrap.cpp (See: https://github.com/Ed94/gencpp)
// This file was generated automatially by gencpp's bootstrap.cpp (See: https://github.com/Ed94/gencpp)
namespace ECode
{

View File

@ -1,6 +1,8 @@
#ifdef GEN_INTELLISENSE_DIRECTIVES
#pragma once
#endif
// This file was generated automatially by gen.bootstrap.cpp (See: https://github.com/Ed94/gencpp)
// This file was generated automatially by gencpp's bootstrap.cpp (See: https://github.com/Ed94/gencpp)
namespace EOperator
{

View File

@ -1,6 +1,8 @@
#ifdef GEN_INTELLISENSE_DIRECTIVES
#pragma once
#endif
// This file was generated automatially by gen.bootstrap.cpp (See: https://github.com/Ed94/gencpp)
// This file was generated automatially by gencpp's bootstrap.cpp (See: https://github.com/Ed94/gencpp)
namespace ESpecifier
{
@ -29,6 +31,7 @@ namespace ESpecifier
Virtual,
Const,
Final,
NoExceptions,
Override,
Pure,
NumSpecifiers
@ -65,6 +68,7 @@ namespace ESpecifier
{ sizeof( "virtual" ), "virtual" },
{ sizeof( "const" ), "const" },
{ sizeof( "final" ), "final" },
{ sizeof( "noexcept" ), "noexcept" },
{ sizeof( "override" ), "override" },
{ sizeof( "= 0" ), "= 0" },
};

View File

@ -1,4 +1,4 @@
// This file was generated automatially by gen.bootstrap.cpp (See: https://github.com/Ed94/gencpp)
// This file was generated automatially by gencpp's bootstrap.cpp (See: https://github.com/Ed94/gencpp)
#pragma once
@ -128,7 +128,7 @@ namespace Parser
{ sizeof( "]" ), "]" },
{ sizeof( "(" ), "(" },
{ sizeof( ")" ), ")" },
{ sizeof( "__comemnt__" ), "__comemnt__" },
{ sizeof( "__comment__" ), "__comment__" },
{ sizeof( "__comment_end__" ), "__comment_end__" },
{ sizeof( "__comment_start__" ), "__comment_start__" },
{ sizeof( "__character__" ), "__character__" },

View File

@ -1,6 +1,8 @@
#ifdef GEN_INTELLISENSE_DIRECTIVES
#pragma once
#include "inlines.hpp"
#include "gen/ast_inlines.hpp"
#endif
#pragma region Constants

View File

@ -1,5 +1,7 @@
#ifdef GEN_INTELLISENSE_DIRECTIVES
#pragma once
#include "interface.hpp"
#endif
void AST::append( AST* other )
{
@ -25,43 +27,6 @@ void AST::append( AST* other )
NumEntries++;
}
char const* AST::debug_str()
{
if ( Parent )
{
char const* fmt = stringize(
\nType : %s
\nParent : %s %s
\nName : %s
);
// These should be used immediately in a log.
// Thus if its desired to keep the debug str
// for multiple calls to bprintf,
// allocate this to proper string.
return str_fmt_buf( fmt
, type_str()
, Parent->Name
, Parent->type_str()
, Name ? Name : ""
);
}
char const* fmt = stringize(
\nType : %s
\nName : %s
);
// These should be used immediately in a log.
// Thus if its desired to keep the debug str
// for multiple calls to bprintf,
// allocate this to proper string.
return str_fmt_buf( fmt
, type_str()
, Name ? Name : ""
);
}
Code& AST::entry( u32 idx )
{
AST** current = & Front;
@ -102,15 +67,21 @@ Code& Code::operator ++()
void CodeClass::add_interface( CodeType type )
{
if ( ! ast->Next )
CodeType possible_slot = ast->ParentType;
if ( possible_slot.ast )
{
ast->Next = type;
ast->Last = ast->Next;
return;
// Were adding an interface to parent type, so we need to make sure the parent type is public.
ast->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.
}
ast->Next->Next = type;
ast->Last = ast->Next->Next;
while ( possible_slot.ast != nullptr )
{
possible_slot.ast = (AST_Type*) possible_slot->Next.ast;
}
possible_slot.ast = type.ast;
}
void CodeParam::append( CodeParam other )
@ -164,14 +135,21 @@ CodeParam& CodeParam::operator ++()
void CodeStruct::add_interface( CodeType type )
{
if ( ! ast->Next )
CodeType possible_slot = ast->ParentType;
if ( possible_slot.ast )
{
ast->Next = type;
ast->Last = ast->Next;
// Were adding an interface to parent type, so we need to make sure the parent type is public.
ast->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.
}
ast->Next->Next = type;
ast->Last = ast->Next->Next;
while ( possible_slot.ast != nullptr )
{
possible_slot.ast = (AST_Type*) possible_slot->Next.ast;
}
possible_slot.ast = type.ast;
}
CodeBody def_body( CodeT type )

View File

@ -1,5 +1,7 @@
#ifdef GEN_INTELLISENSE_DIRECTIVES
#pragma once
#include "ast.cpp"
#endif
internal void init_parser();
internal void deinit_parser();
@ -413,6 +415,8 @@ Code make_code()
}
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 };
@ -422,6 +426,7 @@ Code make_code()
result->Type = ECode::Invalid;
result->ModuleFlags = ModuleFlag::Invalid;
result->NumEntries = 0;
result->Token = -1;
return result;
}

View File

@ -1,5 +1,7 @@
#ifdef GEN_INTELLISENSE_DIRECTIVES
#pragma once
#include "ast_types.hpp"
#endif
#pragma region Gen Interface
@ -68,7 +70,7 @@ CodeFn def_function( StrC name
, CodeSpecifiers specifiers = NoCode, CodeAttributes attributes = NoCode
, ModuleFlag mflags = ModuleFlag::None );
CodeInclude def_include ( StrC content );
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 );

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,7 @@
#ifdef GEN_INTELLISENSE_DIRECTIVES
#pragma once
#include "interface.parsing.cpp"
#endif
sw token_fmt_va( char* buf, uw buf_size, s32 num_tokens, va_list va )
{

View File

@ -1,5 +1,7 @@
#ifdef GEN_INTELLISENSE_DIRECTIVES
#pragma once
#include "interface.cpp"
#endif
#pragma region Upfront
@ -415,12 +417,42 @@ CodeComment def_comment( StrC content )
return CodeInvalid;
}
static char line[ MaxCommentLineLength ];
String cmt_formatted = String::make_reserve( GlobalAllocator, kilobytes(1) );
char const* end = content.Ptr + content.Len;
char const* scanner = content.Ptr;
s32 curr = 0;
do
{
char const* next = scanner;
s32 length = 0;
while ( next != end && scanner[ length ] != '\n' )
{
next = scanner + length;
length++;
}
length++;
str_copy( line, scanner, length );
cmt_formatted.append_fmt( "//%.*s", length, line );
mem_set( line, 0, MaxCommentLineLength );
scanner += length;
}
while ( scanner <= end );
if ( cmt_formatted.back() != '\n' )
cmt_formatted.append( "\n" );
Code
result = make_code();
result->Type = ECode::Comment;
result->Name = get_cached_string( content );
result->Name = get_cached_string( cmt_formatted );
result->Content = result->Name;
cmt_formatted.free();
return (CodeComment) result;
}
@ -820,7 +852,7 @@ CodeFn def_function( StrC name
return result;
}
CodeInclude def_include ( StrC path )
CodeInclude def_include( StrC path, bool foreign )
{
if ( path.Len <= 0 || path.Ptr == nullptr )
{
@ -828,10 +860,14 @@ CodeInclude def_include ( StrC path )
return CodeInvalid;
}
StrC content = foreign ?
to_str( str_fmt_buf( "<%.*s>\n", path.Len, path.Ptr ))
: to_str( str_fmt_buf( "\"%.*s\"\n", path.Len, path.Ptr ));
Code
result = make_code();
result->Type = ECode::Preprocess_Include;
result->Name = get_cached_string( path );
result->Name = get_cached_string( content );
result->Content = result->Name;
return (CodeInclude) result;

View File

@ -1,5 +1,7 @@
#ifdef GEN_INTELLISENSE_DIRECTIVES
#pragma once
#include "gen.hpp"
#endif
#pragma region StaticData

View File

@ -1,5 +1,7 @@
#ifdef GEN_INTELLISENSE_DIRECTIVES
#pragma once
#include "header_start.hpp"
#endif
using LogFailType = sw(*)(char const*, ...);

View File

@ -1,5 +1,7 @@
#pragma once
#include "macros.hpp"
#ifdef GEN_INTELLISENSE_DIRECTIVES
# pragma once
# include "macros.hpp"
#endif
#pragma region Basic Types

View File

@ -1,5 +1,7 @@
#pragma once
#include "printing.hpp"
#ifdef GEN_INTELLISENSE_DIRECTIVES
# pragma once
# include "printing.hpp"
#endif
#pragma region Containers

View File

@ -1,4 +1,6 @@
#pragma once
#ifdef GEN_INTELLISENSE_DIRECTIVES
# pragma once
#endif
#pragma region Debug

View File

@ -1,5 +1,7 @@
#pragma once
#include "basic_types.hpp"
#ifdef GEN_INTELLISENSE_DIRECTIVESj
# pragma once
# include "basic_types.hpp"
#endif
#pragma region Debug

View File

@ -1,5 +1,7 @@
#pragma once
#include "strings.cpp"
#ifdef GEN_INTELLISENSE_DIRECTIVES
# pragma once
# include "strings.cpp"
#endif
#pragma region File Handling

View File

@ -1,5 +1,7 @@
#pragma once
#include "strings.hpp"
#ifdef GEN_INTELLISENSE_DIRECTIVES
# pragma once
# include "strings.hpp"
#endif
#pragma region File Handling

View File

@ -1,5 +1,7 @@
#pragma once
#include "memory.cpp"
#ifdef GEN_INTELLISENSE_DIRECTIVES
# pragma once
# include "memory.cpp"
#endif
#pragma region Hashing

View File

@ -1,5 +1,7 @@
#ifdef GEN_INTELLISENSE_DIRECTIVES
#pragma once
#include "containers.hpp"
#endif
#pragma region Hashing

View File

@ -1,5 +1,7 @@
#pragma once
#include "header_start.hpp"
#ifdef GEN_INTELLISENSE_DIRECTIVES
# pragma once
# include "header_start.hpp"
#endif
#pragma region Macros

View File

@ -1,5 +1,7 @@
#pragma once
#include "printing.cpp"
#ifdef GEN_INTELLISENSE_DIRECTIVES
# pragma once
# include "printing.cpp"
#endif
#pragma region Memory
@ -206,6 +208,132 @@ void* heap_allocator_proc( void* allocator_data, AllocType type, sw size, sw ali
return ptr;
}
#pragma region VirtualMemory
VirtualMemory vm_from_memory( void* data, sw size )
{
VirtualMemory vm;
vm.data = data;
vm.size = size;
return vm;
}
#if defined( GEN_SYSTEM_WINDOWS )
VirtualMemory vm_alloc( void* addr, sw size )
{
VirtualMemory vm;
GEN_ASSERT( size > 0 );
vm.data = VirtualAlloc( addr, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE );
vm.size = size;
return vm;
}
b32 vm_free( VirtualMemory vm )
{
MEMORY_BASIC_INFORMATION info;
while ( vm.size > 0 )
{
if ( VirtualQuery( vm.data, &info, size_of( info ) ) == 0 )
return false;
if ( info.BaseAddress != vm.data || info.AllocationBase != vm.data || info.State != MEM_COMMIT || info.RegionSize > zpl_cast( uw ) vm.size )
{
return false;
}
if ( VirtualFree( vm.data, 0, MEM_RELEASE ) == 0 )
return false;
vm.data = pointer_add( vm.data, info.RegionSize );
vm.size -= info.RegionSize;
}
return true;
}
VirtualMemory vm_trim( VirtualMemory vm, sw lead_size, sw size )
{
VirtualMemory new_vm = { 0 };
void* ptr;
GEN_ASSERT( vm.size >= lead_size + size );
ptr = pointer_add( vm.data, lead_size );
vm_free( vm );
new_vm = vm_alloc( ptr, size );
if ( new_vm.data == ptr )
return new_vm;
if ( new_vm.data )
vm_free( new_vm );
return new_vm;
}
b32 vm_purge( VirtualMemory vm )
{
VirtualAlloc( vm.data, vm.size, MEM_RESET, PAGE_READWRITE );
// NOTE: Can this really fail?
return true;
}
sw virtual_memory_page_size( sw* alignment_out )
{
SYSTEM_INFO info;
GetSystemInfo( &info );
if ( alignment_out )
*alignment_out = info.dwAllocationGranularity;
return info.dwPageSize;
}
#else
# include <sys/mman.h>
# ifndef MAP_ANONYMOUS
# define MAP_ANONYMOUS MAP_ANON
# endif
VirtualMemory vm_alloc( void* addr, sw size )
{
VirtualMemory vm;
GEN_ASSERT( size > 0 );
vm.data = mmap( addr, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0 );
vm.size = size;
return vm;
}
b32 vm_free( VirtualMemory vm )
{
munmap( vm.data, vm.size );
return true;
}
VirtualMemory vm_trim( VirtualMemory vm, sw lead_size, sw size )
{
void* ptr;
sw trail_size;
GEN_ASSERT( vm.size >= lead_size + size );
ptr = pointer_add( vm.data, lead_size );
trail_size = vm.size - lead_size - size;
if ( lead_size != 0 )
vm_free( vm_from_memory(( vm.data, lead_size ) );
if ( trail_size != 0 )
vm_free( vm_from_memory( ptr, trail_size ) );
return vm_from_memory( ptr, size );
}
b32 vm_purge( VirtualMemory vm )
{
int err = madvise( vm.data, vm.size, MADV_DONTNEED );
return err != 0;
}
sw virtual_memory_page_size( sw* alignment_out )
{
// TODO: Is this always true?
sw result = zpl_cast( sw ) sysconf( _SC_PAGE_SIZE );
if ( alignment_out )
*alignment_out = result;
return result;
}
#endif
#pragma endregion VirtualMemory
void* Arena::allocator_proc( void* allocator_data, AllocType type, sw size, sw alignment, void* old_memory, sw old_size, u64 flags )
{
Arena* arena = rcast(Arena*, allocator_data);

View File

@ -1,5 +1,7 @@
#pragma once
#include "debug.hpp"
#ifdef GEN_INTELLISENSE_DIRECTIVES
# pragma once
# include "debug.hpp"
#endif
#pragma region Memory
@ -363,6 +365,33 @@ GEN_IMPL_INLINE void zero_size( void* ptr, sw size )
mem_set( ptr, 0, size );
}
struct VirtualMemory
{
void* data;
sw size;
};
//! Initialize virtual memory from existing data.
VirtualMemory vm_from_memory( void* data, sw size );
//! Allocate virtual memory at address with size.
//! @param addr The starting address of the region to reserve. If NULL, it lets operating system to decide where to allocate it.
//! @param size The size to serve.
VirtualMemory vm_alloc( void* addr, sw size );
//! Release the virtual memory.
b32 vm_free( VirtualMemory vm );
//! Trim virtual memory.
VirtualMemory vm_trim( VirtualMemory vm, sw lead_size, sw size );
//! Purge virtual memory.
b32 gen_vm_purge( VirtualMemory vm );
//! Retrieve VM's page size and alignment.
sw gen_virtual_memory_page_size( sw* alignment_out );
struct Arena
{
static
@ -448,6 +477,45 @@ struct Arena
}
};
// 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;
}
sw size_remaining( sw alignment )
{
return arena.size_remaining( alignment );
}
operator AllocatorInfo()
{
return { Arena::allocator_proc, &arena };
}
Arena arena;
char memory[ Size ];
};
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 ) >;
struct Pool
{
static

View File

@ -1,4 +1,6 @@
#pragma once
#ifdef GEN_INTELLISENSE_DIRECTIVES
# pragma once
#endif
#pragma region ADT

View File

@ -1,4 +1,6 @@
#pragma once
#ifdef GEN_INTELLISENSE_DIRECTIVES
# pragma once
#endif
#pragma region ADT

View File

@ -1,5 +1,7 @@
#pragma once
#include "string_ops.cpp"
#ifdef GEN_INTELLISENSE_DIRECTIVES
# pragma once
# include "string_ops.cpp"
#endif
#pragma region Printing

View File

@ -1,5 +1,7 @@
#pragma once
#include "string_ops.hpp"
#ifdef GEN_INTELLISENSE_DIRECTIVES
# pragma once
# include "string_ops.hpp"
#endif
#pragma region Printing

View File

@ -1,5 +1,7 @@
#pragma once
#include "debug.cpp"
#ifdef GEN_INTELLISENSE_DIRECTIVES
# pragma once
# include "debug.cpp"
#endif
#pragma region String Ops

View File

@ -1,5 +1,7 @@
#pragma once
#include "memory.hpp"
#ifdef GEN_INTELLISENSE_DIRECTIVES
# pragma once
# include "memory.hpp"
#endif
#pragma region String Ops

View File

@ -1,5 +1,7 @@
#pragma once
#include "hashing.cpp"
#ifdef GEN_INTELLISENSE_DIRECTIVES
# pragma once
# include "hashing.cpp"
#endif
#pragma region String

View File

@ -1,5 +1,7 @@
#pragma once
#include "hashing.hpp"
#ifdef GEN_INTELLISENSE_DIRECTIVES
# pragma once
# include "hashing.hpp"
#endif
#pragma region Strings
@ -99,6 +101,11 @@ struct String
bool make_space_for( char const* str, sw add_len );
bool append( char c )
{
return append( & c, 1 );
}
bool append( char const* str )
{
return append( str, str_len( str ) );
@ -213,6 +220,27 @@ struct String
#undef current
}
void strip_space()
{
char* write_pos = Data;
char* read_pos = Data;
while ( * read_pos)
{
if ( ! char_is_space( *read_pos ))
{
*write_pos = *read_pos;
write_pos++;
}
read_pos++;
}
write_pos[0] = '\0'; // Null-terminate the modified string
// Update the length if needed
get_header().Length = write_pos - Data;
}
void trim( char const* cut_set )
{
sw len = 0;
@ -241,14 +269,52 @@ struct String
return trim( " \t\r\n\v\f" );
}
// Debug function that provides a copy of the string with whitespace characters visualized.
String visualize_whitespace() const
{
Header* header = (Header*)(Data - sizeof(Header));
String result = make_reserve(header->Allocator, length() * 2); // Assume worst case for space requirements.
for ( char c : *this )
{
switch ( c )
{
case ' ':
result.append( txt("·") );
break;
case '\t':
result.append( txt("") );
break;
case '\n':
result.append( txt("") );
break;
case '\r':
result.append( txt("") );
break;
case '\v':
result.append( txt("") );
break;
case '\f':
result.append( txt("") );
break;
default:
result.append(c);
break;
}
}
return result;
}
// For-range support
char* begin()
char* begin() const
{
return Data;
}
char* end()
char* end() const
{
Header const&
header = * rcast( Header const*, Data - sizeof( Header ));

View File

@ -1,5 +1,7 @@
#pragma once
#include "filesystem.cpp"
#ifdef GEN_INTELLISENSE_DIRECTIVES
# pragma once
# include "filesystem.cpp"
#endif
#pragma region Timing

View File

@ -1,5 +1,7 @@
#pragma once
#include "filesystem.hpp"
#ifdef GEN_INTELLISENSE_DIRECTIVES
# pragma once
# include "filesystem.hpp"
#endif
#pragma region Timing

View File

@ -21,5 +21,6 @@ Volatile, volatile
Virtual, virtual
Const, const
Final, final
NoExceptions, noexcept
Override, override
Pure, = 0

1 Invalid INVALID
21 Virtual virtual
22 Const const
23 Final final
24 NoExceptions noexcept
25 Override override
26 Pure = 0

View File

@ -15,7 +15,7 @@ BraceSquare_Open, "["
BraceSquare_Close, "]"
Capture_Start, "("
Capture_End, ")"
Comment, "__comemnt__"
Comment, "__comment__"
Comment_End, "__comment_end__"
Comment_Start, "__comment_start__"
Char, "__character__"

1 Invalid __invalid__
15 BraceSquare_Close ]
16 Capture_Start (
17 Capture_End )
18 Comment __comemnt__ __comment__
19 Comment_End __comment_end__
20 Comment_Start __comment_start__
21 Char __character__

View File

@ -396,6 +396,7 @@ if ( $test )
build-simple $includes $unit $executable
Push-Location $path_test
Write-Host $path_test
if ( Test-Path( $executable ) ) {
write-host "`nRunning test generator"
$time_taken = Measure-Command { & $executable
@ -458,7 +459,7 @@ if ( $singleheader -and (Test-Path (Join-Path $path_singleheader "gen/gen.hpp"))
format-cpp $path_gen $include $exclude
}
if ( $test )
if ( $test -and $false )
{
$path_gen = join-path $path_test gen
$include = @(

View File

@ -1,6 +1,4 @@
# Singleheader
`gen.singleheader.cpp` with its own `meson.build` generates the library as a single header `gen.hpp`.
Following the same convention seen in the gb, stb, and zpl libraries.
( Currently WIP )
Creates a single header file version of the library using `gen.singleheader.cpp`.
Follows the same convention seen in the gb, stb, and zpl libraries.

View File

@ -17,7 +17,7 @@ GEN_NS_END
using namespace gen;
constexpr char const* generation_notice =
"// This file was generated automatially by gen.bootstrap.cpp "
"// This file was generated automatially by gencpp's singleheader.cpp"
"(See: https://github.com/Ed94/gencpp)\n\n";
constexpr StrC implementation_guard_start = txt(R"(
@ -48,8 +48,6 @@ global bool generate_builder = true;
global bool generate_editor = true;
global bool generate_scanner = true;
constexpr bool DontSkipInitialDirectives = false;
int gen_main()
{
#define project_dir "../project/"
@ -57,7 +55,7 @@ int gen_main()
Code push_ignores = scan_file( project_dir "helpers/push_ignores.inline.hpp" );
Code pop_ignores = scan_file( project_dir "helpers/pop_ignores.inline.hpp" );
Code single_header_start = scan_file( "components/header_start.hpp", DontSkipInitialDirectives );
Code single_header_start = scan_file( "components/header_start.hpp" );
Builder
header = Builder::open( "gen/gen.hpp" );
@ -71,7 +69,7 @@ int gen_main()
if ( generate_gen_dep )
{
Code header_start = scan_file( project_dir "dependencies/header_start.hpp", DontSkipInitialDirectives );
Code header_start = scan_file( project_dir "dependencies/header_start.hpp" );
Code macros = scan_file( project_dir "dependencies/macros.hpp" );
Code basic_types = scan_file( project_dir "dependencies/basic_types.hpp" );
Code debug = scan_file( project_dir "dependencies/debug.hpp" );

35
test/CURSED_TYPEDEF.h Normal file
View File

@ -0,0 +1,35 @@
#include <functional>
class MyClass;
enum class MyEnum : short { VAL1, VAL2 };
struct OuterStruct {
union NamedUnion {
struct InnerStruct {
double d;
char c;
} inner;
int i;
} unionInstance;
};
template<typename T, int N = alignof(double)>
struct TemplateStruct {
T member[N];
};
template<>
struct TemplateStruct<int, 10> {
int specialMember[10];
};
typedef decltype(nullptr) (MyClass::*InsaneComplexTypeDef)(
decltype((MyEnum::VAL1 == MyEnum::VAL2) ? 1 : 2.0)
(TemplateStruct<decltype(OuterStruct().unionInstance.inner), 5>::*ptr)[5][alignof(double)],
std::function<void *(TemplateStruct<int, 10>&&,
void (MyClass::*memFnPtr)(TemplateStruct<decltype(OuterStruct().unionInstance.inner)>))>,
int (MyClass::*&refToMemFnPtr)(TemplateStruct<int, 10>),
int (TemplateStruct<int, 10>::*memberPointer)[10],
char&&...
) volatile const && noexcept;

View File

@ -0,0 +1,13 @@
# Test : Eskil Steenberg's Game Pipeline
***Note: This validation test has not been implemented yet.***
Repo : https://github.com/valiet/quel_solaar
This is a AST reconstruction test of the gamepipeline library.
1. Download the library
2. Grab all header and source file paths
3. Generate an ast for each file and serialize it to a file called <name of file>.gen.<h/c>
4. Reconstruct the ast from the generated file
5. Compare the original ast to the reconstructed ast

View File

15
test/Godot/Readme.md Normal file
View File

@ -0,0 +1,15 @@
# Test : Godot full AST reconstruction and compile validation
***Note: This validation test has not been implemented yet.***
Repo : https://github.com/godotengine/godot
* Download the Unreal source code
* Find paths of every header and source file
* Generate an ast for each file and serialize it to a file called `<name of file>.gen.<h/c>`
* Reconstruct the ast from the generated file
* Compare the original ast to the reconstructed ast
* If all ASTs are considered valid, overwrite the original files with the generated files
* Compile the engine.
Currently the most involved test planned for the library.

View File

0
test/Godot/validate.ps1 Normal file
View File

25
test/Unreal/Readme.md Normal file
View File

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

0
test/Unreal/validate.ps1 Normal file
View File

View File

18
test/ZPL-C/Readme.md Normal file
View File

@ -0,0 +1,18 @@
# Test : ZPL-C Reconstruction
***Note: This validation test has not been implemented yet.***
Repo : https://github.com/zpl-c/zpl
This is a AST reconstruction test of the ZPL-C library.
Much of the dependency code used in gencpp is derived from the ZPL-C library.
In the future I could directly generate that related code from the ZPL-C library.
For now it just does the following:
1. Download the ZPL-C library
2. Grab all header and source file paths
3. Generate an ast for each file and serialize it to a file called <name of file>.gen.<h/c>
4. Reconstruct the ast from the generated file
5. Compare the original ast to the reconstructed ast

0
test/ZPL-C/validate.ps1 Normal file
View File

View File

View File

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

View File

@ -4,6 +4,11 @@
#define GEN_ENFORCE_STRONG_CODE_TYPES
#define GEN_EXPOSE_BACKEND
#define GEN_BENCHMARK
#define GEN_GLOBAL_BUCKET_SIZE megabytes(10)
#define GEN_CODE_POOL_BLOCK_SIZE megabytes(32)
#define GEN_STRING_ARENA_SIZE megabytes(1)
#include "gen.hpp"
#include "gen.builder.hpp"

View File

@ -7,7 +7,7 @@
#include "gen.builder.cpp"
#include "sanity.cpp"
#include "SOA.cpp"
#include "test.singleheader_ast.cpp"
#include "validate.singleheader.cpp"
int gen_main()
{
@ -18,8 +18,7 @@ int gen_main()
// check_SOA();
check_singleheader_ast();
check_singleheader_ast();
return 0;
}
#endif

View File

@ -1,33 +0,0 @@
#define GEN_DEFINE_LIBRARY_CODE_CONSTANTS
#define GEN_ENFORCE_STRONG_CODE_TYPES
#define GEN_EXPOSE_BACKEND
#define GEN_BENCHMARK
#include "gen.hpp"
#include "gen.builder.hpp"
#include "gen.scanner.hpp"
using namespace gen;
void check_singleheader_ast()
{
#define project_dir "../"
gen::init();
log_fmt("\ncheck_singleheader_ast:\n");
FileContents file = file_read_contents( GlobalAllocator, true, project_dir "singleheader/gen/gen.hpp" );
u64 time_start = time_rel_ms();
CodeBody ast = parse_global_body( { file.size, (char const*)file.data } );
log_fmt("\nAst generated. Time taken: %llu ms\n", time_rel_ms() - time_start);
log_fmt("\nSerializng ast:\n");
time_start = time_rel_ms();
Builder
builder = Builder::open( "gen/singleheader_copy.gen.hpp" );
builder.print( ast );
builder.write();
log_fmt("passed!! Time taken: %llu ms\n", time_rel_ms() - time_start);
gen::deinit();
}

View File

@ -12,7 +12,7 @@ void check_upfront()
log_fmt("\nupfront: ");
gen::init();
// TODO
gen::deinit();
log_fmt("Passed!\n");

View File

@ -0,0 +1,65 @@
#define GEN_DEFINE_LIBRARY_CODE_CONSTANTS
#define GEN_ENFORCE_STRONG_CODE_TYPES
#define GEN_EXPOSE_BACKEND
#define GEN_BENCHMARK
#include "gen.hpp"
#include "gen.builder.hpp"
#include "gen.scanner.hpp"
using namespace gen;
#ifdef GEN_SYSTEM_WINDOWS
#include <process.h>
#endif
void check_singleheader_ast()
{
#define root_dir "../"
gen::init();
log_fmt("\ncheck_singleheader_ast:\n");
FileContents file = file_read_contents( GlobalAllocator, true, root_dir "singleheader/gen/gen.hpp" );
u64 time_start = time_rel_ms();
CodeBody ast = parse_global_body( { file.size, (char const*)file.data } );
log_fmt("\nAst generated. Time taken: %llu ms\n", time_rel_ms() - time_start);
log_fmt("\nSerializng ast:\n");
time_start = time_rel_ms();
Builder
builder = Builder::open( "gen/singleheader_copy.gen.hpp" );
builder.print( ast );
builder.write();
log_fmt("Serialized. Time taken: %llu ms\n", time_rel_ms() - time_start);
// Need to execute clang format on the generated file to get it to match the original.
#define script_path root_dir "scripts/"
#define clang_format "clang-format "
#define cf_format_inplace "-i "
#define cf_style "-style=file:" "C:/projects/gencpp/scripts/.clang-format "
#define cf_verbose "-verbose "
log_fmt("\nRunning clang-format on generated file:\n");
system( clang_format cf_format_inplace cf_style cf_verbose "gen/singleheader_copy.gen.hpp" );
log_fmt("clang-format finished reformatting.\n");
#undef script_path
#undef cf_cmd
#undef cf_format_inplace
#undef cf_style
#undef cf_verbse
FileContents file_gen = file_read_contents( GlobalAllocator, true, "gen/singleheader_copy.gen.hpp" );
log_fmt("\nReconstructing from generated file:\n");
time_start = time_rel_ms();
CodeBody ast_gen = parse_global_body( { file_gen.size, (char const*)file_gen.data } );
log_fmt("\nAst generated. Time taken: %llu ms\n\n", time_rel_ms() - time_start);
time_start = time_rel_ms();
if ( ast.is_equal( ast_gen ) )
log_fmt( "\nPassed!: AST passed validation!\n" );
else
log_fmt( "\nFailed: AST did not pass validation\n" );
log_fmt( "Time taken: %llu ms\n", time_rel_ms() - time_start );
gen::deinit();
}

View File

@ -1,3 +0,0 @@
// Constructs an AST from the singlheader generated gen files, then serializes it to a set of files.
// Using the new set of serialized files, reconstructs the AST and then serializes it again (to different set of files).
// The two sets of serialized files should be identical. (Verified by comparing the file hashes)