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.
This commit is contained in:
Edward R. Gonzalez 2023-08-22 16:01:50 -04:00
parent 49a2cd7b2c
commit 5e79e8ba65
35 changed files with 697 additions and 19 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

@ -872,23 +872,603 @@ String AST::to_string()
bool AST::is_equal( AST* other )
{
/*
AST values are either some u32 value, a cached string, or a pointer to another AST.
u32 values are compared by value.
Cached strings are compared by pointer.
AST nodes are compared with AST::is_equal.
*/
if ( other == nullptr )
return false;
if ( Type != other->Type )
return false;
switch ( Type )
{
case ECode::Typedef:
case ECode::Typename:
using namespace ECode;
case NewLine:
case Access_Public:
case Access_Protected:
case Access_Private:
case Preprocess_Else:
case Preprocess_EndIf:
return true;
case Comment:
case Execution:
case PlatformAttributes:
case Untyped:
{
if ( Prev ? ! Prev->is_equal( other->Prev ) : other->Prev != nullptr )
return false;
if ( Next ? ! Next->is_equal( other->Next ) : other->Next != nullptr )
return false;
return Content == other->Content;
}
case Class_Fwd:
case Struct_Fwd:
{
if ( Name != other->Name )
return false;
if ( ParentType != other->ParentType )
return false;
if ( ParentAccess != other->ParentAccess )
return false;
if ( Attributes ? ! Attributes->is_equal( other->Attributes ) : other->Attributes != nullptr )
return false;
if ( Prev ? ! Prev->is_equal( other->Prev ) : other->Prev != nullptr )
return false;
if ( Next ? ! Next->is_equal( other->Next ) : other->Next != nullptr )
return false;
return true;
}
case Class:
case Struct:
{
if ( ModuleFlags != other->ModuleFlags )
return false;
if ( Name != other->Name )
return false;
if ( ParentType != other->ParentType )
return false;
if ( ParentAccess != other->ParentAccess )
return false;
if ( Attributes ? ! Attributes->is_equal( other->Attributes ) : other->Attributes != nullptr )
return false;
if ( Body ? ! Body->is_equal( other->Body ) : other->Body != nullptr )
return false;
if ( Prev ? ! Prev->is_equal( other->Prev ) : other->Prev != nullptr )
return false;
return true;
}
case Constructor:
{
if ( InitializerList ? ! InitializerList->is_equal( other->InitializerList ) : other->InitializerList != nullptr )
return false;
if ( Params ? ! Params->is_equal( other->Params ) : other->Params != nullptr )
return false;
if ( Body ? ! Body->is_equal( other->Body ) : other->Body != nullptr )
return false;
if ( Prev ? ! Prev->is_equal( other->Prev ) : other->Prev != nullptr )
return false;
if ( Next ? ! Next->is_equal( other->Next ) : other->Next != nullptr )
return false;
return true;
}
case Constructor_Fwd:
{
if ( InitializerList ? ! InitializerList->is_equal( other->InitializerList ) : other->InitializerList != nullptr )
return false;
if ( Params ? ! Params->is_equal( other->Params ) : other->Params != nullptr )
return false;
if ( Prev ? ! Prev->is_equal( other->Prev ) : other->Prev != nullptr )
return false;
if ( Next ? ! Next->is_equal( other->Next ) : other->Next != nullptr )
return false;
return true;
}
case Destructor:
{
if ( Specs ? ! Specs->is_equal( other->Specs ) : other->Specs != nullptr )
return false;
if ( Body ? ! Body->is_equal( other->Body ) : other->Body != nullptr )
return false;
if ( Prev ? ! Prev->is_equal( other->Prev ) : other->Prev != nullptr )
return false;
if ( Next ? ! Next->is_equal( other->Next ) : other->Next != nullptr )
return false;
return true;
}
case Destructor_Fwd:
{
if ( Specs ? ! Specs->is_equal( other->Specs ) : other->Specs != nullptr )
return false;
if ( Prev ? ! Prev->is_equal( other->Prev ) : other->Prev != nullptr )
return false;
if ( Next ? ! Next->is_equal( other->Next ) : other->Next != nullptr )
return false;
return true;
}
case Enum:
case Enum_Class:
{
if ( ModuleFlags != other->ModuleFlags )
return false;
if ( Name != other->Name )
return false;
if ( Attributes ? ! Attributes->is_equal( other->Attributes ) : other->Attributes != nullptr )
return false;
if ( UnderlyingType ? ! UnderlyingType->is_equal( other->UnderlyingType ) : other->UnderlyingType != nullptr )
return false;
if ( Body ? ! Body->is_equal( other->Body ) : other->Body != nullptr )
return false;
if ( Prev ? ! Prev->is_equal( other->Prev ) : other->Prev != nullptr )
return false;
if ( Next ? ! Next->is_equal( other->Next ) : other->Next != nullptr )
return false;
return true;
}
case Enum_Fwd:
case Enum_Class_Fwd:
{
if ( ModuleFlags != other->ModuleFlags )
return false;
if ( Name != other->Name )
return false;
if ( Attributes ? ! Attributes->is_equal( other->Attributes ) : other->Attributes != nullptr )
return false;
if ( UnderlyingType ? ! UnderlyingType->is_equal( other->UnderlyingType ) : other->UnderlyingType != nullptr )
return false;
if ( Prev ? ! Prev->is_equal( other->Prev ) : other->Prev != nullptr )
return false;
if ( Next ? ! Next->is_equal( other->Next ) : other->Next != nullptr )
return false;
return true;
}
case Extern_Linkage:
{
if ( Name != other->Name )
return false;
if ( Body ? ! Body->is_equal( other->Body ) : other->Body != nullptr )
return false;
if ( Prev ? ! Prev->is_equal( other->Prev ) : other->Prev != nullptr )
return false;
if ( Next ? ! Next->is_equal( other->Next ) : other->Next != nullptr )
return false;
return true;
}
case Friend:
{
if ( Name != other->Name )
return false;
if ( Declaration ? ! Declaration->is_equal( other->Declaration ) : other->Declaration != nullptr )
return false;
if ( Prev ? ! Prev->is_equal( other->Prev ) : other->Prev != nullptr )
return false;
if ( Next ? ! Next->is_equal( other->Next ) : other->Next != nullptr )
return false;
return true;
}
case Function:
{
if ( ModuleFlags != other->ModuleFlags )
return false;
if ( Name != other->Name )
return false;
if ( ReturnType ? ! ReturnType->is_equal( other->ReturnType ) : other->ReturnType != nullptr )
return false;
if ( Attributes ? ! Attributes->is_equal( other->Attributes ) : other->Attributes != nullptr )
return false;
if ( Specs ? ! Specs->is_equal( other->Specs ) : other->Specs != nullptr )
return false;
if ( Params ? ! Params->is_equal( other->Params ) : other->Params != nullptr )
return false;
if ( Body ? ! Body->is_equal( other->Body ) : other->Body != nullptr )
return false;
if ( Prev ? ! Prev->is_equal( other->Prev ) : other->Prev != nullptr )
return false;
if ( Next ? ! Next->is_equal( other->Next ) : other->Next != nullptr )
return false;
return true;
}
case Function_Fwd:
{
if ( ModuleFlags != other->ModuleFlags )
return false;
if ( Name != other->Name )
return false;
if ( ReturnType ? ! ReturnType->is_equal( other->ReturnType ) : other->ReturnType != nullptr )
return false;
if ( Attributes ? ! Attributes->is_equal( other->Attributes ) : other->Attributes != nullptr )
return false;
if ( Specs ? ! Specs->is_equal( other->Specs ) : other->Specs != nullptr )
return false;
if ( Params ? ! Params->is_equal( other->Params ) : other->Params != nullptr )
return false;
if ( Prev ? ! Prev->is_equal( other->Prev ) : other->Prev != nullptr )
return false;
if ( Next ? ! Next->is_equal( other->Next ) : other->Next != nullptr )
return false;
return true;
}
case Module:
{
if ( ModuleFlags != other->ModuleFlags )
return false;
if ( Name != other->Name )
return false;
if ( Prev ? ! Prev->is_equal( other->Prev ) : other->Prev != nullptr )
return false;
if ( Next ? ! Next->is_equal( other->Next ) : other->Next != nullptr )
return false;
return true;
}
case Namespace:
{
if ( ModuleFlags != other->ModuleFlags )
return false;
if ( Name != other->Name )
return false;
if ( Body ? ! Body->is_equal( other->Body ) : other->Body != nullptr )
return false;
if ( Prev ? ! Prev->is_equal( other->Prev ) : other->Prev != nullptr )
return false;
if ( Next ? ! Next->is_equal( other->Next ) : other->Next != nullptr )
return false;
return true;
}
case Operator:
case Operator_Member:
{
if ( ModuleFlags != other->ModuleFlags )
return false;
if ( Name != other->Name )
return false;
if ( ReturnType ? ! ReturnType->is_equal( other->ReturnType ) : other->ReturnType != nullptr )
return false;
if ( Attributes ? ! Attributes->is_equal( other->Attributes ) : other->Attributes != nullptr )
return false;
if ( Specs ? ! Specs->is_equal( other->Specs ) : other->Specs != nullptr )
return false;
if ( Params ? ! Params->is_equal( other->Params ) : other->Params != nullptr )
return false;
if ( Body ? ! Body->is_equal( other->Body ) : other->Body != nullptr )
return false;
if ( Prev ? ! Prev->is_equal( other->Prev ) : other->Prev != nullptr )
return false;
if ( Next ? ! Next->is_equal( other->Next ) : other->Next != nullptr )
return false;
return true;
}
case Operator_Fwd:
case Operator_Member_Fwd:
{
if ( ModuleFlags != other->ModuleFlags )
return false;
if ( Name != other->Name )
return false;
if ( ReturnType ? ! ReturnType->is_equal( other->ReturnType ) : other->ReturnType != nullptr )
return false;
if ( Attributes ? ! Attributes->is_equal( other->Attributes ) : other->Attributes != nullptr )
return false;
if ( Specs ? ! Specs->is_equal( other->Specs ) : other->Specs != nullptr )
return false;
if ( Params ? ! Params->is_equal( other->Params ) : other->Params != nullptr )
return false;
if ( Prev ? ! Prev->is_equal( other->Prev ) : other->Prev != nullptr )
return false;
if ( Next ? ! Next->is_equal( other->Next ) : other->Next != nullptr )
return false;
return true;
}
case Operator_Cast:
{
if ( Name != other->Name )
return false;
if ( Specs ? ! Specs->is_equal( other->Specs ) : other->Specs != nullptr )
return false;
if ( ValueType ? ! ValueType->is_equal( other->ValueType ) : other->ValueType != nullptr )
return false;
if ( Body ? ! Body->is_equal( other->Body ) : other->Body != nullptr )
return false;
if ( Prev ? ! Prev->is_equal( other->Prev ) : other->Prev != nullptr )
return false;
if ( Next ? ! Next->is_equal( other->Next ) : other->Next != nullptr )
return false;
return true;
}
case Operator_Cast_Fwd:
{
if ( Name != other->Name )
return false;
if ( Specs ? ! Specs->is_equal( other->Specs ) : other->Specs != nullptr )
return false;
if ( ValueType ? ! ValueType->is_equal( other->ValueType ) : other->ValueType != nullptr )
return false;
if ( Prev ? ! Prev->is_equal( other->Prev ) : other->Prev != nullptr )
return false;
if ( Next ? ! Next->is_equal( other->Next ) : other->Next != nullptr )
return false;
return true;
}
case Parameters:
{
if ( NumEntries > 1 )
{
if ( NumEntries != other->NumEntries )
return false;
AST* curr = this;
AST* curr_other = other;
while ( curr != nullptr )
{
if ( ! curr->is_equal( curr_other ) )
return false;
curr = curr->Next;
curr_other = curr_other->Next;
}
return true;
}
if ( Name != other->Name )
return false;
if ( ValueType ? ! ValueType->is_equal( other->ValueType ) : other->ValueType != nullptr )
return false;
if ( Value ? ! Value->is_equal( other->Value ) : other->Value != nullptr )
return false;
if ( ArrExpr ? ! ArrExpr->is_equal( other->ArrExpr ) : other->ArrExpr != nullptr )
return false;
return true;
}
case Preprocess_Define:
{
if ( Name != other->Name )
return false;
if ( Content != other->Content )
return false;
if ( Prev ? ! Prev->is_equal( other->Prev ) : other->Prev != nullptr )
return false;
if ( Next ? ! Next->is_equal( other->Next ) : other->Next != nullptr )
return false;
return true;
}
case Preprocess_If:
case Preprocess_IfDef:
case Preprocess_IfNotDef:
case Preprocess_ElIf:
{
if ( Content != other->Content )
return false;
if ( Prev ? ! Prev->is_equal( other->Prev ) : other->Prev != nullptr )
return false;
if ( Next ? ! Next->is_equal( other->Next ) : other->Next != nullptr )
return false;
return true;
}
case Preprocess_Include:
case Preprocess_Pragma:
{
if ( Content != other->Content )
return false;
if ( Prev ? ! Prev->is_equal( other->Prev ) : other->Prev != nullptr )
return false;
if ( Next ? ! Next->is_equal( other->Next ) : other->Next != nullptr )
return false;
return true;
}
case Specifiers:
{
if ( NumEntries != other->NumEntries )
return false;
if ( Name != other->Name )
return false;
for ( s32 idx = 0; idx < NumEntries; ++idx )
{
if ( ArrSpecs[ idx ] != other->ArrSpecs[ idx ] )
return false;
}
if ( Prev ? ! Prev->is_equal( other->Prev ) : other->Prev != nullptr )
return false;
if ( Next ? ! Next->is_equal( other->Next ) : other->Next != nullptr )
return false;
return true;
}
case Template:
{
if ( ModuleFlags != other->ModuleFlags )
return false;
if ( Name != other->Name )
return false;
if ( Params ? ! Params->is_equal( other->Params ) : other->Params != nullptr )
return false;
if ( Declaration ? ! Declaration->is_equal( other->Declaration ) : other->Declaration != nullptr )
return false;
if ( Prev ? ! Prev->is_equal( other->Prev ) : other->Prev != nullptr )
return false;
if ( Next ? ! Next->is_equal( other->Next ) : other->Next != nullptr )
return false;
return true;
}
case Typedef:
{
if ( IsFunction != other->IsFunction )
return false;
if ( ModuleFlags != other->ModuleFlags )
return false;
if ( Name != other->Name )
return false;
if ( UnderlyingType != other->UnderlyingType )
return false;
if ( Prev ? ! Prev->is_equal( other->Prev ) : other->Prev != nullptr )
return false;
if ( Next ? ! Next->is_equal( other->Next ) : other->Next != nullptr )
return false;
return true;
}
case Typename:
{
if ( Name != other->Name )
return false;
if ( Specs ? ! Specs->is_equal( other->Specs ) : other->Specs != nullptr )
return false;
if ( ArrExpr ? ! ArrExpr->is_equal( other->ArrExpr ) : other->ArrExpr != nullptr )
return false;
if ( Prev ? ! Prev->is_equal( other->Prev ) : other->Prev != nullptr )
return false;
if ( Next ? ! Next->is_equal( other->Next ) : other->Next != nullptr )
return false;
return true;
}
case Union:
{
if ( ModuleFlags != other->ModuleFlags )
return false;
if ( Name != other->Name )
return false;
if ( Attributes ? ! Attributes->is_equal( other->Attributes ) : other->Attributes != nullptr )
return false;
if ( Body ? ! Body->is_equal( other->Body ) : other->Body != nullptr )
return false;
if ( Prev ? ! Prev->is_equal( other->Prev ) : other->Prev != nullptr )
return false;
if ( Next ? ! Next->is_equal( other->Next ) : other->Next != nullptr )
return false;
return true;
}
case Using:
case Using_Namespace:
{
if ( ModuleFlags != other->ModuleFlags )
return false;
if ( Name != other->Name )
return false;
if ( Attributes ? ! Attributes->is_equal( other->Attributes ) : other->Attributes != nullptr )
return false;
if ( UnderlyingType ? ! UnderlyingType->is_equal( other->UnderlyingType ) : other->UnderlyingType != nullptr )
return false;
if ( Prev ? ! Prev->is_equal( other->Prev ) : other->Prev != nullptr )
return false;
if ( Next ? ! Next->is_equal( other->Next ) : other->Next != nullptr )
return false;
return true;
}
case Variable:
{
if ( ModuleFlags != other->ModuleFlags )
return false;
if ( Name != other->Name )
return false;
if ( Attributes ? ! Attributes->is_equal( other->Attributes ) : other->Attributes != nullptr )
return false;
if ( Specs ? ! Specs->is_equal( other->Specs ) : other->Specs != nullptr )
return false;
if ( ValueType ? ! ValueType->is_equal( other->ValueType ) : other->ValueType != nullptr )
return false;
if ( BitfieldSize ? ! BitfieldSize->is_equal( other->BitfieldSize ) : other->BitfieldSize != nullptr )
return false;
if ( Value ? ! Value->is_equal( other->Value ) : other->Value != nullptr )
return false;
if ( Prev ? ! Prev->is_equal( other->Prev ) : other->Prev != nullptr )
return false;
if ( Next ? ! Next->is_equal( other->Next ) : other->Next != nullptr )
return false;
return true;
}
case Class_Body:
case Enum_Body:
case Export_Body:
case Global_Body:
case Namespace_Body:
case Struct_Body:
case Union_Body:
{
if ( NumEntries != other->NumEntries )
return false;
if ( Front != other->Front )
return false;
if ( Back != other->Back )
return false;
AST* curr = Front;
AST* curr_other = other->Front;
while ( curr != nullptr )
{
if ( ! curr->is_equal( curr_other ) )
return false;
curr = curr->Next;
curr_other = curr_other->Next;
}
return true;
}
}
return true;
}

View File

@ -89,7 +89,7 @@ struct AST_Constructor
Code Prev;
Code Next;
Code Parent;
StringCached Name;
char _PAD_NAME_[ sizeof(StringCached) ];
CodeT Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ];
};
@ -125,7 +125,7 @@ struct AST_Destructor
Code Prev;
Code Next;
Code Parent;
StringCached Name;
char _PAD_NAME_[ sizeof(StringCached) ];
CodeT Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ];
};
@ -158,10 +158,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;

View File

@ -413,6 +413,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 };

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 "test.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

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

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)