From c895772cfffc982138c008e0d1aeb86b85c50dbe Mon Sep 17 00:00:00 2001 From: Ed_ Date: Sun, 15 Dec 2024 18:22:59 -0500 Subject: [PATCH] fixes etc for gasa gen --- Project/Source/GasaEditor/GasaEditor.Build.cs | 60 +- .../GasaEditor/GasaGen/AttributeSets.cpp | 112 +- .../GasaEditor/GasaGen/ChangeBPActionMenu.cpp | 15 +- .../GasaGen/ChangeEditorContentList.cpp | 55 +- .../GasaEditor/GasaGen/DevOptionsCache.cpp | 45 +- Project/Source/GasaEditor/GasaGen/GasaGen.cpp | 130 +- .../GasaEditor/GasaGen/GasaGen_Common.h | 141 +- .../GasaEditor/GasaGen/gencpp/gen.builder.cpp | 4 +- .../GasaEditor/GasaGen/gencpp/gen.builder.hpp | 13 +- .../Source/GasaEditor/GasaGen/gencpp/gen.cpp | 57 +- .../GasaEditor/GasaGen/gencpp/gen.dep.cpp | 1146 +++++++++++++++- .../GasaEditor/GasaGen/gencpp/gen.dep.hpp | 445 +++++- .../Source/GasaEditor/GasaGen/gencpp/gen.hpp | 26 +- .../GasaEditor/GasaGen/gencpp/gen.scanner.cpp | 1197 ++--------------- .../GasaEditor/GasaGen/gencpp/gen.scanner.hpp | 429 ------ Project/Source/GasaGen/gen.builder.cpp | 4 +- Project/Source/GasaGen/gen.cpp | 4 + Project/Source/GasaGen/gen.dep.hpp | 2 +- Project/Source/GasaGen/gen.hpp | 5 +- 19 files changed, 2066 insertions(+), 1824 deletions(-) diff --git a/Project/Source/GasaEditor/GasaEditor.Build.cs b/Project/Source/GasaEditor/GasaEditor.Build.cs index 31a6a4a..4c9b397 100644 --- a/Project/Source/GasaEditor/GasaEditor.Build.cs +++ b/Project/Source/GasaEditor/GasaEditor.Build.cs @@ -1,42 +1,50 @@ +using UnrealBuildTool; using ModuleRules = UnrealBuildTool.ModuleRules; using ReadOnlyTargetRules = UnrealBuildTool.ReadOnlyTargetRules; public class GasaEditor : ModuleRules { - public GasaEditor(ReadOnlyTargetRules Target) : base(Target) - { - #region Engine - PrivateIncludePathModuleNames.AddRange(new string[] { - "Core", - "CoreUObject", - "Engine", - }); - PrivateDependencyModuleNames.AddRange(new string[] { - "Core", - "Engine", - "CoreUObject", + public GasaEditor(ReadOnlyTargetRules Target) : base(Target) + { + #region Engine + + PrivateIncludePathModuleNames.AddRange(new string[] + { + "Core", + "CoreUObject", + "Engine", + }); + PrivateDependencyModuleNames.AddRange(new string[] + { + "Core", + "Engine", + "CoreUObject", "EditorStyle", - "PropertyEditor", - "SlateCore", - "Slate", - "UMG", - "UnrealEd", - }); - #endregion Engine - + "PropertyEditor", + "SlateCore", + "Slate", + "UMG", + "UnrealEd", + }); + + #endregion Engine + PublicIncludePaths.Add("GasaEditor"); PrivateDependencyModuleNames.Add("Gasa"); - - bWarningsAsErrors = false; - ShadowVariableWarningLevel = UnrealBuildTool.WarningLevel.Off; + + bWarningsAsErrors = false; + ShadowVariableWarningLevel = UnrealBuildTool.WarningLevel.Off; UndefinedIdentifierWarningLevel = UnrealBuildTool.WarningLevel.Off; - + // gencpp related defines - PublicDefinitions.Add("Build_Debug=1"); PublicDefinitions.Add("GEN_TIME=1"); PublicDefinitions.Add("GEN_EXECUTION_EXPRESSION_SUPPORT=0"); PublicDefinitions.Add("GEN_EXPOSE_BACKEND=1"); PublicDefinitions.Add("GEN_PARSER_DISABLE_MACRO_TYPEDEF=0"); + PublicDefinitions.Add("GEN_DONT_USE_NAMESPACE=0"); + PublicDefinitions.Add("GEN_BUILD_DEBUG=1"); + PublicDefinitions.Add("GEN_SUPPORT_CPP_REFERENCES=1"); + + OptimizeCode = CodeOptimization.Never; } } - diff --git a/Project/Source/GasaEditor/GasaGen/AttributeSets.cpp b/Project/Source/GasaEditor/GasaGen/AttributeSets.cpp index 58b6e31..3704877 100644 --- a/Project/Source/GasaEditor/GasaGen/AttributeSets.cpp +++ b/Project/Source/GasaEditor/GasaGen/AttributeSets.cpp @@ -36,22 +36,22 @@ void gen_attribute_set_from_table( UDataTable* table, FString asset_name ) check( asset_name.StartsWith(TEXT("DT_") )) asset_name = asset_name.RightChop(3); - String str_AssetName = to_string(asset_name); + Str str_AssetName = to_string(asset_name); - String class_name = String::fmt_buf(GlobalAllocator, "U%S", str_AssetName); - String header_file_name = String::fmt_buf(GlobalAllocator, "%S.h", str_AssetName); - String inlines_file_name = String::fmt_buf(GlobalAllocator, "%S_Inlines.h", str_AssetName); - String path_header_file = String::fmt_buf(GlobalAllocator, path_gasa_ability_system "%S.h", str_AssetName); - String path_inlines_file = String::fmt_buf(GlobalAllocator, path_gasa_ability_system "%S_Inlines.h", str_AssetName); - String path_source_file = String::fmt_buf(GlobalAllocator, path_gasa_ability_system "%S.cpp", str_AssetName); - String uht_include_file = String::fmt_buf(GlobalAllocator, "%S.generated.h", str_AssetName); + Str class_name = StrBuilder::fmt_buf(gen_ctx.Allocator_Temp, "U%S", str_AssetName); + Str header_file_name = StrBuilder::fmt_buf(gen_ctx.Allocator_Temp, "%S.h", str_AssetName); + Str inlines_file_name = StrBuilder::fmt_buf(gen_ctx.Allocator_Temp, "%S_Inlines.h", str_AssetName); + Str path_header_file = StrBuilder::fmt_buf(gen_ctx.Allocator_Temp, path_gasa_ability_system "%S.h", str_AssetName); + Str path_inlines_file = StrBuilder::fmt_buf(gen_ctx.Allocator_Temp, path_gasa_ability_system "%S_Inlines.h", str_AssetName); + Str path_source_file = StrBuilder::fmt_buf(gen_ctx.Allocator_Temp, path_gasa_ability_system "%S.cpp", str_AssetName); + Str uht_include_file = StrBuilder::fmt_buf(gen_ctx.Allocator_Temp, "%S.generated.h", str_AssetName); - CodeType type_UAttributeSet = def_type( txt("UAttributeSet") ); - CodeComment generation_notice = def_comment(txt("Generated by GasaEditor/GasaGen/GasaGen_AttributeSets.cpp")); + CodeTypename type_UAttributeSet = def_type( txt("UAttributeSet") ); + CodeComment generation_notice = def_comment(txt("Generated by GasaEditor/GasaGen/GasaGen_AttributeSets.cpp")); CodeAttributes api_attribute = def_attributes( UModule_GASA_API->Name); - Builder header = builder_open( path_header_file ); + Builder header = gasa_builder_open( path_header_file ); { header.print(generation_notice); header.print(pragma_once); @@ -65,7 +65,7 @@ void gen_attribute_set_from_table( UDataTable* table, FString asset_name ) gen::CodeClass attribute_set_class = {}; { - CodeBody body = def_body( CodeT::Class_Body ); + CodeBody body = def_body( CT_Class_Body ); { body.append( UHT_GENERATED_BODY); body.append( access_public ); @@ -76,15 +76,15 @@ void gen_attribute_set_from_table( UDataTable* table, FString asset_name ) // Generate UPROPERTIES for each attribute field, organized by category for ( TPair< FName, TArray>& attributes : AttributesByCategory ) { - String category_name = to_string(attributes.Key); - CodeComment category_cmt = def_comment(token_fmt("category_name", (StrC)category_name, " Attributes")); + Str category_name = to_string(attributes.Key); + CodeComment category_cmt = def_comment(token_fmt("category_name", category_name, " Attributes")); body.append(category_cmt); body.append(fmt_newline); for (FAttributeSetField attribute : attributes.Value) { Code field_uproperty = code_fmt( - "category", (StrC)to_string(attribute.Category), - "property", (StrC)to_string(attribute.Name), + "category", to_string(attribute.Category), + "property", to_string(attribute.Name), stringize( UPROPERTY(ReplicatedUsing = Client_OnRep_, EditAnywhere, BlueprintReadWrite, Category = "Attributes|") FGameplayAttributeData ; @@ -104,7 +104,7 @@ void gen_attribute_set_from_table( UDataTable* table, FString asset_name ) body.append(fmt_newline); body.append(umeta_UFUNCTION); body.append(fmt_newline); - body.append(code_fmt("property", (StrC)to_string(attribute.Name), stringize( + body.append(code_fmt("property", to_string(attribute.Name), stringize( void Client_OnRep_(FGameplayAttributeData& Prev); ))); } @@ -118,8 +118,8 @@ void gen_attribute_set_from_table( UDataTable* table, FString asset_name ) for (FAttributeSetField attribute : attributes.Value) { CodeFn generated_get_attribute = parse_function(token_fmt( - "class_name", (StrC)class_name, - "property", (StrC)to_string(attribute.Name), + "class_name", class_name, + "property", to_string(attribute.Name), stringize( static FGameplayAttribute GetAttribute() { @@ -135,7 +135,7 @@ void gen_attribute_set_from_table( UDataTable* table, FString asset_name ) for ( TPair< FName, TArray>& attributes : AttributesByCategory ) for (FAttributeSetField attribute : attributes.Value) { - body.append(code_fmt("property", (StrC)to_string(attribute.Name), + body.append(code_fmt("property", to_string(attribute.Name), stringize( FORCEINLINE float Get() const { @@ -154,7 +154,7 @@ void gen_attribute_set_from_table( UDataTable* table, FString asset_name ) for ( TPair< FName, TArray>& attributes : AttributesByCategory ) for (FAttributeSetField attribute : attributes.Value) { - body.append(code_fmt("property", (StrC)to_string(attribute.Name), + body.append(code_fmt("property", to_string(attribute.Name), stringize( FORCEINLINE void Set(float NewVal); ))); @@ -180,10 +180,10 @@ void gen_attribute_set_from_table( UDataTable* table, FString asset_name ) body.append(fmt_newline); } - attribute_set_class = def_class( class_name, body - , type_UAttributeSet, AccessSpec::Public + attribute_set_class = def_class( class_name, { body + , type_UAttributeSet, AccessSpec_Public , api_attribute - ); + }); header.print(UHT_UCLASS); header.print(attribute_set_class); } @@ -192,7 +192,7 @@ void gen_attribute_set_from_table( UDataTable* table, FString asset_name ) format_file(path_header_file); } - Builder inlines = builder_open( path_inlines_file ); + Builder inlines = gasa_builder_open( path_inlines_file ); { inlines.print(generation_notice); inlines.print(pragma_once); @@ -201,7 +201,7 @@ void gen_attribute_set_from_table( UDataTable* table, FString asset_name ) inlines.print(def_include(txt("AbilitySystemComponent.h"))); inlines.print(fmt_newline); - CodeBody body = def_body(ECode::Global_Body); + CodeBody body = def_body(CT_Global_Body); { body.append(def_pragma(txt("region Attribute Setters"))); { @@ -209,8 +209,8 @@ void gen_attribute_set_from_table( UDataTable* table, FString asset_name ) for (FAttributeSetField attribute : attributes.Value) { CodeFn generated_get_attribute = parse_function(token_fmt( - "class_name", (StrC)class_name, - "property", (StrC)to_string(attribute.Name), + "class_name", class_name, + "property", to_string(attribute.Name), stringize( FORCEINLINE void ::Set(float NewVal) { @@ -230,7 +230,7 @@ void gen_attribute_set_from_table( UDataTable* table, FString asset_name ) inlines.print(fmt_newline); CodeNS ns_gasa = parse_namespace(token_fmt( - "class_name", (StrC)class_name, + "class_name", class_name, stringize( namespace Gasa { @@ -247,7 +247,7 @@ void gen_attribute_set_from_table( UDataTable* table, FString asset_name ) format_file(path_inlines_file); } - Builder source = builder_open( path_source_file ); + Builder source = gasa_builder_open( path_source_file ); { source.print(generation_notice); header.print(fmt_newline); @@ -260,7 +260,7 @@ void gen_attribute_set_from_table( UDataTable* table, FString asset_name ) source.print(def_include(txt("Networking/GasaNetLibrary.h"))); source.print(def_include(txt("GameplayEffectExtension.h"))); { - CodeBody body = def_body(CodeT::Global_Body); + CodeBody body = def_body(CT_Global_Body); body.append(fmt_newline); CodeConstructor constructor_for_UGasaAttributeSet = parse_constructor(code( @@ -278,8 +278,8 @@ void gen_attribute_set_from_table( UDataTable* table, FString asset_name ) for (FAttributeSetField attribute : attributes.Value) { CodeFn field_impl = parse_function(token_fmt( - "class_name", (StrC)class_name, - "property", (StrC)to_string(attribute.Name), + "class_name", class_name, + "property", to_string(attribute.Name), "from_notice", txt("\n// From GAMEPLAYATTRIBUTE_REPNOTIFY\n"), stringize( void ::Client_OnRep_(FGameplayAttributeData & Prev) @@ -298,8 +298,8 @@ void gen_attribute_set_from_table( UDataTable* table, FString asset_name ) CodeFn PostGameplayEffectExecute; CodeFn PreAttributeChange; { - CodeBody pre_attribute_clamps = def_body(CodeT::Function_Body); - CodeBody post_attribute_clamps = def_body(CodeT::Function_Body); + CodeBody pre_attribute_clamps = def_body(CT_Function_Body); + CodeBody post_attribute_clamps = def_body(CT_Function_Body); // Generate field clamping ops for the pre & post functions { @@ -311,22 +311,22 @@ void gen_attribute_set_from_table( UDataTable* table, FString asset_name ) for (TPair< FName, TArray>& attributes : AttributesByCategory) for (FAttributeSetField attribute : attributes.Value) { - String clamp_min; + Str clamp_min; if (attribute.bUseMinAttribute) - clamp_min = get_cached_string(token_fmt("MinName", (StrC)to_string(attribute.MinAttribute), "Get()")); + clamp_min = cache_str(token_fmt("MinName", to_string(attribute.MinAttribute), "Get()")); else - clamp_min = String::fmt_buf(GlobalAllocator, "%f", attribute.MinValue); + clamp_min = StrBuilder::fmt_buf(gen_ctx.Allocator_Temp, "%f", attribute.MinValue); - String clamp_max; + Str clamp_max; if (attribute.bUseMaxAttribute) - clamp_max = get_cached_string(token_fmt("MaxName", (StrC)to_string(attribute.MaxAttribute), "Get()")); + clamp_max = cache_str(token_fmt("MaxName", to_string(attribute.MaxAttribute), "Get()")); else - clamp_max = String::fmt_buf(GlobalAllocator, "%f", attribute.MaxValue); + clamp_max = StrBuilder::fmt_buf(gen_ctx.Allocator_Temp, "%f", attribute.MaxValue); pre_attribute_clamps.append(code_fmt( - "field", (StrC)to_string(attribute.Name), - "clamp_min", (StrC)clamp_min, - "clamp_max", (StrC)clamp_max, + "field", to_string(attribute.Name), + "clamp_min", clamp_min, + "clamp_max", clamp_max, stringize( if (Attribute == GetAttribute()) { @@ -335,9 +335,9 @@ void gen_attribute_set_from_table( UDataTable* table, FString asset_name ) ))); post_attribute_clamps.append(code_fmt( - "field", (StrC)to_string(attribute.Name), - "clamp_min", (StrC)clamp_min, - "clamp_max", (StrC)clamp_max, + "field", to_string(attribute.Name), + "clamp_min", clamp_min, + "clamp_max", clamp_max, stringize( if (Data.EvaluatedData.Attribute == GetAttribute()) { @@ -353,8 +353,8 @@ void gen_attribute_set_from_table( UDataTable* table, FString asset_name ) } PreAttributeChange = parse_function(token_fmt( - "class_name", (StrC)class_name, - "attribute_clamps", (StrC)pre_attribute_clamps.to_string(), + "class_name", class_name, + "attribute_clamps", pre_attribute_clamps.to_strbuilder().to_str(), stringize( void ::PreAttributeChange(FGameplayAttribute const& Attribute, float& NewValue) { @@ -365,8 +365,8 @@ void gen_attribute_set_from_table( UDataTable* table, FString asset_name ) ))); PostGameplayEffectExecute = parse_function(token_fmt( - "class_name", (StrC)class_name, - "attribute_clamps", (StrC)post_attribute_clamps.to_string(), + "class_name", class_name, + "attribute_clamps", post_attribute_clamps.to_strbuilder().to_str(), stringize( void ::PostGameplayEffectExecute(FGameplayEffectModCallbackData const& Data) { @@ -387,23 +387,23 @@ void gen_attribute_set_from_table( UDataTable* table, FString asset_name ) CodeFn GetLifetimeOfReplicatedProps; { - CodeBody field_lifetimes = def_body(CodeT::Function_Body); + CodeBody field_lifetimes = def_body(CT_Function_Body); field_lifetimes.append(fmt_newline); field_lifetimes.append(fmt_newline); for (TPair< FName, TArray>& attributes : AttributesByCategory) for (FAttributeSetField attribute : attributes.Value) { field_lifetimes.append(code_fmt( - "class_name", (StrC)class_name, - "property", (StrC)to_string(attribute.Name), + "class_name", class_name, + "property", to_string(attribute.Name), stringize( DOREPLIFETIME_DEFAULT_GAS( , ); ))); } GetLifetimeOfReplicatedProps = parse_function(token_fmt( - "class_name", (StrC)class_name, - "property_lifetimes", (StrC)(field_lifetimes.to_string()), + "class_name", class_name, + "property_lifetimes", field_lifetimes.to_strbuilder().to_str(), stringize( void ::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const { diff --git a/Project/Source/GasaEditor/GasaGen/ChangeBPActionMenu.cpp b/Project/Source/GasaEditor/GasaGen/ChangeBPActionMenu.cpp index 0dad5c9..1859e92 100644 --- a/Project/Source/GasaEditor/GasaGen/ChangeBPActionMenu.cpp +++ b/Project/Source/GasaEditor/GasaGen/ChangeBPActionMenu.cpp @@ -2,7 +2,7 @@ #include "ChangeBPActionMenu.h" #include "GasaGen_Common.h" -constexpr StrC SBlueprintActionMenu_Construct_Replacement = txt(R"( +constexpr Str SBlueprintActionMenu_Construct_Replacement = txt(R"( void SBlueprintActionMenu::Construct( const FArguments& InArgs, TSharedPtr InEditor ) { bActionExecuted = false; @@ -244,23 +244,22 @@ void change_SBlueprintActionMenu_Construct() #define path_SBlueprintActionMenuCpp \ R"(C:\projects\Unreal\Surgo\UE\Engine\Source\Editor\Kismet\Private\SBlueprintActionMenu.cpp)" - FileContents content = file_read_contents( GlobalAllocator, true, path_SBlueprintActionMenuCpp ); - CodeBody parsed_SBlueprintActionMenu = parse_global_body( StrC { content.size, (char const*)content.data }); + FileContents content = file_read_contents( gen_ctx.Allocator_Temp, true, path_SBlueprintActionMenuCpp ); + CodeBody parsed_SBlueprintActionMenu = parse_global_body( Str { (char const*)content.data, content.size }); CodeFn signature_to_change = parse_function( code( void SBlueprintActionMenu::Construct( const FArguments& InArgs, TSharedPtr InEditor ) {} )); - CodeBody changed_SBlueprintActionMenu = def_body(ECode::Global_Body); + CodeBody changed_SBlueprintActionMenu = def_body(CT_Global_Body); for ( Code code : parsed_SBlueprintActionMenu ) { switch ( code->Type ) { - using namespace ECode; - case Function: - CodeFn function_def = code.cast(); + case CT_Function: + CodeFn function_def = cast(CodeFn, code); - if ( String::are_equal(function_def->Name, signature_to_change->Name) + if ( str_are_equal(function_def->Name, signature_to_change->Name) && function_def->Params.is_equal(signature_to_change->Params)) { code = parse_function( SBlueprintActionMenu_Construct_Replacement ); diff --git a/Project/Source/GasaEditor/GasaGen/ChangeEditorContentList.cpp b/Project/Source/GasaEditor/GasaGen/ChangeEditorContentList.cpp index 3928f20..7611bd9 100644 --- a/Project/Source/GasaEditor/GasaGen/ChangeEditorContentList.cpp +++ b/Project/Source/GasaEditor/GasaGen/ChangeEditorContentList.cpp @@ -3,7 +3,7 @@ #include "GasaGen_Common.h" #include "GasaEditorCommon.h" -constexpr StrC SAssetView_Construct_Replacement = txt(R"( +constexpr Str SAssetView_Construct_Replacement = txt(R"( void SAssetView::Construct( const FArguments& InArgs ) { ViewCorrelationGuid = FGuid::NewGuid(); @@ -391,7 +391,7 @@ void SAssetView::Construct( const FArguments& InArgs ) } })"); -constexpr StrC SAssetView_GetThumbnailScale_Replacement = txt(R"( +constexpr Str SAssetView_GetThumbnailScale_Replacement = txt(R"( float SAssetView::GetThumbnailScale() const { float BaseScale; @@ -423,7 +423,7 @@ float SAssetView::GetThumbnailScale() const return BaseScale * GetTickSpaceGeometry().Scale; })"); -constexpr StrC SPropertyMenuAssetPicker_Construct_Replacement = txt(R"( +constexpr Str SPropertyMenuAssetPicker_Construct_Replacement = txt(R"( void SPropertyMenuAssetPicker::Construct( const FArguments& InArgs ) { CurrentObject = InArgs._InitialObject; @@ -595,27 +595,26 @@ void change_EditorContentList() #define path_PropertyEditorAssetConstantsHeader \ R"(C:\Projects\Unreal\Surgo\UE\Engine\Source\Editor\PropertyEditor\Private\UserInterface\PropertyEditor\PropertyEditorAssetConstants.h)" - FileContents content = file_read_contents( GlobalAllocator, true, path_PropertyEditorAssetConstantsHeader ); - CodeBody parsed_PropertyEditorAssetConstantsHeader = parse_global_body( StrC { content.size, (char const*)content.data }); + FileContents content = file_read_contents( gen_ctx.Allocator_Temp, true, path_PropertyEditorAssetConstantsHeader ); + CodeBody parsed_PropertyEditorAssetConstantsHeader = parse_global_body( Str { (char const*)content.data, content.size }); - CodeBody changed_PropertyEditorAssetConstantsHeader = def_body(ECode::Global_Body); + CodeBody changed_PropertyEditorAssetConstantsHeader = def_body(CT_Global_Body); for ( Code code : parsed_PropertyEditorAssetConstantsHeader ) { switch ( code->Type ) { - using namespace ECode; - case Namespace: - CodeNS ns = code.cast(); + case CT_Namespace: + CodeNS ns = cast(CodeNS, code); for ( Code ns_code : ns->Body ) { switch ( ns_code->Type ) { - case Variable: - CodeVar var = ns_code.cast(); + case CT_Variable: + CodeVar var = cast(CodeVar, ns_code); if ( var->Name.starts_with(txt("ContentBrowserWindowSize")) ) { // Swap value with new value - var->Value->Content = get_cached_string(txt("300.0f, 600.0f")); + var->Value->Content = cache_str(txt("300.0f, 600.0f")); Gasa::LogEditor("Swapped: " + to_fstring(var->Name)); } @@ -639,8 +638,8 @@ void change_EditorContentList() #define path_SAssetView \ R"(C:\projects\Unreal\Surgo\UE\Engine\Source\Editor\ContentBrowser\Private\SAssetView.cpp)" - FileContents content = file_read_contents( GlobalAllocator, true, path_SAssetView ); - CodeBody parsed_SAssetViewCpp = parse_global_body( StrC { content.size, (char const*)content.data }); + FileContents content = file_read_contents( gen_ctx.Allocator_Temp, true, path_SAssetView ); + CodeBody parsed_SAssetViewCpp = parse_global_body( Str { (char const*)content.data, content.size }); CodeFn signature_Construct = parse_function( code( void SAssetView::Construct( const FArguments& InArgs ) {} @@ -649,24 +648,23 @@ void change_EditorContentList() float SAssetView::GetThumbnailScale() const {} )); - CodeBody changed_SAssetViewCpp = def_body(ECode::Global_Body); + CodeBody changed_SAssetViewCpp = def_body(CT_Global_Body); for ( Code code : parsed_SAssetViewCpp ) { switch ( code->Type ) { - using namespace ECode; - case Function: + case CT_Function: { - CodeFn function_def = code.cast(); + CodeFn function_def = cast(CodeFn, code); - if ( String::are_equal(function_def->Name, signature_Construct->Name) - && function_def->Params.is_equal(signature_Construct->Params)) + if ( str_are_equal(function_def->Name, signature_Construct->Name) + && function_def->Params && function_def->Params.is_equal(signature_Construct->Params)) { code = parse_function( SAssetView_Construct_Replacement ); Gasa::LogEditor("Swapped: " + to_fstring(function_def->Name)); } - else if ( String::are_equal(function_def->Name, signature_GetThumbnailScale->Name) - && function_def->Params.is_equal(signature_GetThumbnailScale->Params)) + else if ( str_are_equal(function_def->Name, signature_GetThumbnailScale->Name) + && function_def->Params && function_def->Params.is_equal(signature_GetThumbnailScale->Params)) { code = parse_function( SAssetView_GetThumbnailScale_Replacement ); Gasa::LogEditor("Swapped: " + to_fstring(function_def->Name)); @@ -689,24 +687,23 @@ void change_EditorContentList() #define path_SPropertyMenuAssetPicker \ R"(C:\projects\Unreal\Surgo\UE\Engine\Source\Editor\PropertyEditor\Private\UserInterface\PropertyEditor\SPropertyMenuAssetPicker.cpp)" - FileContents content = file_read_contents( GlobalAllocator, true, path_SPropertyMenuAssetPicker ); - CodeBody parsed = parse_global_body( StrC { content.size, (char const*)content.data }); + FileContents content = file_read_contents( gen_ctx.Allocator_Temp, true, path_SPropertyMenuAssetPicker ); + CodeBody parsed = parse_global_body( Str { (char const*)content.data, content.size }); CodeFn signature = parse_function( code( void SPropertyMenuAssetPicker::Construct( const FArguments& InArgs ) {} )); - CodeBody changed = def_body(ECode::Global_Body); + CodeBody changed = def_body(CT_Global_Body); for ( Code code : parsed ) { switch ( code->Type ) { - using namespace ECode; - case Function: + case CT_Function: { - CodeFn function_def = code.cast(); + CodeFn function_def = cast(CodeFn, code); - if ( String::are_equal(function_def->Name, signature->Name) + if ( str_are_equal(function_def->Name, signature->Name) && function_def->Params.is_equal(signature->Params)) { code = parse_function( SPropertyMenuAssetPicker_Construct_Replacement ); diff --git a/Project/Source/GasaEditor/GasaGen/DevOptionsCache.cpp b/Project/Source/GasaEditor/GasaGen/DevOptionsCache.cpp index e6c9b67..9432370 100644 --- a/Project/Source/GasaEditor/GasaGen/DevOptionsCache.cpp +++ b/Project/Source/GasaEditor/GasaGen/DevOptionsCache.cpp @@ -8,38 +8,38 @@ void generate_DevOptionsCache() { - Array GasaDevOptions_UPROPERTIES = Array::init(GlobalAllocator); + Array GasaDevOptions_UPROPERTIES = Array::init(gen_ctx.Allocator_Temp); { CodeBody header_GasaDevOptions = parse_file( path_module_gasa "GasaDevOptions.h" ); - CodeClass UGasaDevOptions = NoCode; + CodeClass UGasaDevOptions = NullCode; for (Code entry : header_GasaDevOptions) { - if ( entry->Type == ECode::Class && entry->Name.starts_with( txt("UGasaDevOptions")) ) + if ( entry->Type == CT_Class && entry->Name.starts_with( txt("UGasaDevOptions")) ) { - UGasaDevOptions = entry.cast(); + UGasaDevOptions = cast(CodeClass, entry); break; } } for (Code member = UGasaDevOptions->Body.begin(); member != UGasaDevOptions->Body.end(); ++ member) { - if ( member->Type == ECode::Untyped && member->Name.starts_with(str_UPROPERTY) ) + if ( member->Type == CT_Untyped && member->Name.starts_with(str_UPROPERTY) ) ++ member; - if ( member->Type == ECode::Variable + if ( member->Type == CT_Variable && ( member->ValueType->Name.starts_with( txt("TArray< TSoftObjectPtr")) || member->ValueType->Name.starts_with( txt("TSoftClassPtr")) || member->ValueType->Name.starts_with( txt("TSoftObjectPtr")) ) ) - GasaDevOptions_UPROPERTIES.append(member.cast()); + GasaDevOptions_UPROPERTIES.append(cast(CodeVar, member)); } } CodeComment generation_notice = def_comment(txt("Generated by GasaGen/GasaGen_DevOptionsCache.cpp")); - CodeType t_UClassPtr = parse_type(code(UClass*)); - CodeType t_UObjectPtr = parse_type(code(UObject*)); - CodeType t_Array_UObjectPtr = parse_type(code(TArray< UObject* >)); + CodeTypename t_UClassPtr = parse_type(code(UClass*)); + CodeTypename t_UObjectPtr = parse_type(code(UObject*)); + CodeTypename t_Array_UObjectPtr = parse_type(code(TArray< UObject* >)); - Builder header = builder_open( path_module_gasa "GasaDevOptionsCache.h" ); + Builder header = gasa_builder_open( path_module_gasa "GasaDevOptionsCache.h" ); { header.print( generation_notice ); header.print( pragma_once ); @@ -50,7 +50,7 @@ void generate_DevOptionsCache() header.print( UHT_USTRUCT ); CodeStruct FGasaDevOptionsCache; { - CodeBody body = def_body(ECode::Struct_Body); + CodeBody body = def_body(CT_Struct_Body); { body.append(UHT_GENERATED_BODY); body.append(fmt_newline); @@ -72,7 +72,7 @@ void generate_DevOptionsCache() body.append(fmt_newline); body.append( parse_function(code( void CachedDevOptions(); ))); } - FGasaDevOptionsCache = parse_struct( token_fmt( "body", (StrC)body.to_string(), stringize( + FGasaDevOptionsCache = parse_struct( token_fmt( "body", body.to_strbuilder().to_str(), stringize( struct GASA_API FGasaDevOptionsCache { }; @@ -84,15 +84,15 @@ void generate_DevOptionsCache() format_file( path_module_gasa "GasaDevOptionsCache.h" ); } - Builder source = builder_open( path_module_gasa "GasaDevOptionsCache.cpp" ); + Builder source = gasa_builder_open( path_module_gasa "GasaDevOptionsCache.cpp" ); { - Array GasaDevOptions_Includes = Array::init(GlobalAllocator); + Array GasaDevOptions_Includes = Array::init(gen_ctx.Allocator_Temp); { CodeBody source_GasaDevOptions = parse_file( path_module_gasa "GasaDevOptions.cpp"); for ( Code entry : source_GasaDevOptions ) { - if ( entry->Type == ECode::Preprocess_Include ) - GasaDevOptions_Includes.append( entry.cast() ); + if ( entry->Type == CT_Preprocess_Include ) + GasaDevOptions_Includes.append( cast(CodeInclude, entry)); } } @@ -105,17 +105,17 @@ void generate_DevOptionsCache() source.print( parse_using(code( using namespace Gasa; ))); source.print(fmt_newline); - CodeBody cached_property_assignments = def_body(ECode::Function_Body); + CodeBody cached_property_assignments = def_body(CT_Function_Body); { cached_property_assignments.append(fmt_newline); cached_property_assignments.append(fmt_newline); for (CodeVar var : GasaDevOptions_UPROPERTIES) { - if ( var->ValueType.to_string().starts_with(txt("TArray")) ) + if ( var->ValueType->Name.starts_with(txt("TArray")) ) { #pragma push_macro("TEXT") #undef TEXT - Code assignment = code_fmt( "property_array", (StrC)var->Name, stringize( + Code assignment = code_fmt( "property_array", var->Name, stringize( for ( auto& entry : DevOpts-> ) { .Push( entry.LoadSynchronous() ); @@ -132,7 +132,7 @@ void generate_DevOptionsCache() #pragma push_macro("TEXT") #undef TEXT - Code assignment = code_fmt( "property", (StrC)var->Name, stringize( + Code assignment = code_fmt( "property", var->Name, stringize( = DevOpts-> .LoadSynchronous(); ensureMsgf( != nullptr, TEXT(" is null, DO NOT RUN PIE or else you may get a crash if not handled in BP or C++")); )); @@ -144,7 +144,7 @@ void generate_DevOptionsCache() } CodeFn CachedDevOptions = parse_function( token_fmt( - "cached_property_assignments", (StrC)cached_property_assignments.to_string(), + "cached_property_assignments", cached_property_assignments.to_strbuilder().to_str(), stringize( void FGasaDevOptionsCache::CachedDevOptions() { @@ -163,4 +163,3 @@ void generate_DevOptionsCache() #pragma pop_macro("ensureMsgf") #pragma pop_macro("GASA_API") - diff --git a/Project/Source/GasaEditor/GasaGen/GasaGen.cpp b/Project/Source/GasaEditor/GasaGen/GasaGen.cpp index 60bb570..28c584a 100644 --- a/Project/Source/GasaEditor/GasaGen/GasaGen.cpp +++ b/Project/Source/GasaEditor/GasaGen/GasaGen.cpp @@ -10,8 +10,8 @@ #define LOCTEXT_NAMESPACE "GasaEditor" -global String Project_Path; -global String Root_Path; +global Str Project_Path; +global Str Root_Path; global Code UHT_GENERATED_BODY; global Code UHT_UCLASS; @@ -19,6 +19,8 @@ global Code UHT_UPROPERTY; global Code UHT_USTRUCT; global Code UModule_GASA_API; +global Context gen_ctx = {}; + void Execute_GasaModule_Codegen() { FScopedSlowTask SlowTask(100.0f, LOCTEXT("RunningGasaGen", "Running GasaGen...")); @@ -28,7 +30,13 @@ void Execute_GasaModule_Codegen() { Gasa::LogEditor("Executing: Gasa Module code generation."); - gen::init(); + if (gen_ctx.Allocator_Temp.Proc) { + gen::reset(& gen_ctx); + } + else + { + gen::init( & gen_ctx); + } FString ue_project_path = FPaths::ConvertRelativePathToFull(FPaths::ProjectDir()); FPaths::NormalizeDirectoryName(ue_project_path); @@ -38,8 +46,8 @@ void Execute_GasaModule_Codegen() FPaths::NormalizeDirectoryName(ue_root_path); char const* ue_ansi_rooot_path = TCHAR_TO_ANSI(*ue_project_path); - Project_Path = String::make_length(GlobalAllocator, ue_ansi_project_path, ue_project_path.Len()); - Root_Path = String::make_length(GlobalAllocator, ue_ansi_rooot_path, ue_root_path.Len()); + Project_Path = StrBuilder::make_length(gen_ctx.Allocator_Temp, ue_ansi_project_path, ue_project_path.Len()); + Root_Path = StrBuilder::make_length(gen_ctx.Allocator_Temp, ue_ansi_rooot_path, ue_root_path.Len()); // Initialize Globals { @@ -66,62 +74,70 @@ void Execute_GasaModule_Codegen() } // Populate Defines - { - PreprocessorDefines.append(get_cached_string(str_DECLARE_CLASS)); - PreprocessorDefines.append(get_cached_string(str_DECLARE_DELEGATE_RetVal_OneParam)); - PreprocessorDefines.append(get_cached_string(str_DECLARE_DELEGATE_RetVal_ThreeParams)); - PreprocessorDefines.append(get_cached_string(str_DECLARE_DELEGATE_SixParams)); - PreprocessorDefines.append(get_cached_string(str_DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam)); - PreprocessorDefines.append(get_cached_string(str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_FiveParams)); - PreprocessorDefines.append(get_cached_string(str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_FourParams)); - PreprocessorDefines.append(get_cached_string(str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_NineParams)); - PreprocessorDefines.append(get_cached_string(str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_OneParam)); - PreprocessorDefines.append(get_cached_string(str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_SevenParams)); - PreprocessorDefines.append(get_cached_string(str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_TwoParams)); - PreprocessorDefines.append(get_cached_string(str_DECLARE_EVENT_ThreeParams)); - PreprocessorDefines.append(get_cached_string(str_DECLARE_EVENT_TwoParams)); - PreprocessorDefines.append(get_cached_string(str_DECLARE_FUNCTION)); - PreprocessorDefines.append(get_cached_string(str_DECLARE_LOG_CATEGORY_EXTERN)); - PreprocessorDefines.append(get_cached_string(str_DECLARE_MULTICAST_DELEGATE_OneParam)); - PreprocessorDefines.append(get_cached_string(str_DECLARE_MULTICAST_DELEGATE_ThreeParams)); - PreprocessorDefines.append(get_cached_string(str_DECLARE_MULTICAST_DELEGATE_TwoParams)); - PreprocessorDefines.append(get_cached_string(str_DECLARE_TS_MULTICAST_DELEGATE_OneParam)); - PreprocessorDefines.append(get_cached_string(str_DECLARE_TS_MULTICAST_DELEGATE_TwoParams)); - PreprocessorDefines.append(get_cached_string(str_DECLARE_TS_MULTICAST_DELEGATE_ThreeParams)); - PreprocessorDefines.append(get_cached_string(str_DEFINE_ACTORDESC_TYPE)); - PreprocessorDefines.append(get_cached_string(str_DEFINE_DEFAULT_OBJECT_INITIALIZER_CONSTRUCTOR_CALL)); - PreprocessorDefines.append(get_cached_string(str_ENUM_CLASS_FLAGS)); - PreprocessorDefines.append(get_cached_string(str_FORCEINLINE_DEBUGGABLE)); - // PreprocessorDefines.append( get_cached_string(str_FORCEINLINE)); - PreprocessorDefines.append(get_cached_string(str_GENERATED_BODY)); - PreprocessorDefines.append(get_cached_string(str_GENERATED_UCLASS_BODY)); - PreprocessorDefines.append(get_cached_string(str_GENERATED_USTRUCT_BODY)); - PreprocessorDefines.append(get_cached_string(str_PRAGMA_DISABLE_DEPRECATION_WARNINGS)); - PreprocessorDefines.append(get_cached_string(str_PRAGMA_ENABLE_DEPRECATION_WARNINGS)); - PreprocessorDefines.append(get_cached_string(str_PROPERTY_BINDING_IMPLEMENTATION)); - PreprocessorDefines.append(get_cached_string(str_RESULT_DECL)); - PreprocessorDefines.append(get_cached_string(str_SLATE_BEGIN_ARGS)); - PreprocessorDefines.append(get_cached_string(str_SLATE_END_ARGS)); - PreprocessorDefines.append(get_cached_string(str_TEXT)); - PreprocessorDefines.append(get_cached_string(str_UCLASS)); - PreprocessorDefines.append(get_cached_string(str_UENUM)); - PreprocessorDefines.append(get_cached_string(str_UFUNCTION)); - PreprocessorDefines.append(get_cached_string(str_UMETA)); - PreprocessorDefines.append(get_cached_string(str_UPARAM)); - PreprocessorDefines.append(get_cached_string(str_UPROPERTY)); - PreprocessorDefines.append(get_cached_string(str_USTRUCT)); - PreprocessorDefines.append(get_cached_string(str_UE_REQUIRES)); - } + register_macros( args( + (Macro { str_DECLARE_CLASS, MT_Statement, MF_Functional }), + (Macro { str_DECLARE_DELEGATE_RetVal_OneParam, MT_Statement, MF_Functional }), + (Macro { str_DECLARE_DELEGATE_RetVal_ThreeParams, MT_Statement, MF_Functional }), + (Macro { str_DECLARE_DELEGATE_SixParams, MT_Statement, MF_Functional }), + (Macro { str_DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam, MT_Statement, MF_Functional }), + (Macro { str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_FiveParams, MT_Statement, MF_Functional }), + (Macro { str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_FourParams, MT_Statement, MF_Functional }), + (Macro { str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_NineParams, MT_Statement, MF_Functional }), + (Macro { str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_OneParam, MT_Statement, MF_Functional }), + (Macro { str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_SevenParams, MT_Statement, MF_Functional }), + (Macro { str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_TwoParams, MT_Statement, MF_Functional }), + (Macro { str_DECLARE_EVENT_ThreeParams, MT_Statement, MF_Functional }), + (Macro { str_DECLARE_EVENT_TwoParams, MT_Statement, MF_Functional }), + (Macro { str_DECLARE_FUNCTION, MT_Statement, MF_Functional }), + (Macro { str_DECLARE_LOG_CATEGORY_EXTERN, MT_Statement, MF_Functional | MF_Allow_As_Definition }), + (Macro { str_DECLARE_MULTICAST_DELEGATE_OneParam, MT_Statement, MF_Functional }), + (Macro { str_DECLARE_MULTICAST_DELEGATE_ThreeParams, MT_Statement, MF_Functional }), + (Macro { str_DECLARE_MULTICAST_DELEGATE_TwoParams, MT_Statement, MF_Functional }), + (Macro { str_DECLARE_TS_MULTICAST_DELEGATE_OneParam, MT_Statement, MF_Functional }), + (Macro { str_DECLARE_TS_MULTICAST_DELEGATE_TwoParams, MT_Statement, MF_Functional }), + (Macro { str_DECLARE_TS_MULTICAST_DELEGATE_ThreeParams, MT_Statement, MF_Functional }), + (Macro { str_DEFINE_ACTORDESC_TYPE, MT_Statement, MF_Functional }), + (Macro { str_DEFINE_DEFAULT_OBJECT_INITIALIZER_CONSTRUCTOR_CALL, MT_Statement, MF_Functional }), + (Macro { str_ENUM_CLASS_FLAGS, MT_Statement, MF_Functional }), + (Macro { str_GENERATED_BODY, MT_Statement, MF_Functional }), + (Macro { str_GENERATED_UCLASS_BODY, MT_Statement, MF_Functional }), + (Macro { str_GENERATED_USTRUCT_BODY, MT_Statement, MF_Functional }), + (Macro { str_PRAGMA_DISABLE_DEPRECATION_WARNINGS, MT_Statement, MF_Null | MF_Allow_As_Attribute }), + (Macro { str_PRAGMA_ENABLE_DEPRECATION_WARNINGS, MT_Statement, MF_Null | MF_Allow_As_Attribute }), + (Macro { str_PROPERTY_BINDING_IMPLEMENTATION, MT_Statement, MF_Functional }), + (Macro { str_RESULT_DECL, MT_Expression, MF_Functional }), + (Macro { str_SLATE_BEGIN_ARGS, MT_Statement, MF_Functional | MF_Expects_Body }), + (Macro { str_SLATE_END_ARGS, MT_Statement, MF_Functional }), + (Macro { str_TEXT, MT_Expression, MF_Functional }), + (Macro { str_UCLASS, MT_Statement, MF_Functional }), + (Macro { str_UENUM, MT_Statement, MF_Functional }), + (Macro { str_UFUNCTION, MT_Statement, MF_Functional }), + (Macro { str_UMETA, MT_Expression, MF_Functional }), + (Macro { str_UPARAM, MT_Expression, MF_Functional }), + (Macro { str_UPROPERTY, MT_Statement, MF_Functional }), + (Macro { str_USTRUCT, MT_Statement, MF_Functional }), + (Macro { str_UE_REQUIRES, MT_Expression, MF_Functional }), + (Macro { str_UE_DEPRECATED, MT_Statement, MF_Functional | MF_Allow_As_Attribute }), + (Macro { str_ACTOR_HAS_LABELS, MT_Expression, MF_Null }), + (Macro { str_HIDE_ACTOR_TRANSFORM_FUNCTIONS, MT_Statement, MF_Functional }), + (Macro { str_SCENECOMPONENT_QUAT_TOLERANCE, MT_Expression, MF_Null }), + (Macro { str_SCENECOMPONENT_ROTATOR_TOLERANCE, MT_Expression, MF_Null }), + (Macro { str_GAMEPLAYATTRIBUTE_REPNOTIFY, MT_Statement, MF_Functional }), + (Macro { str_GAMEPLAYATTRIBUTE_PROPERTY_GETTER, MT_Statement, MF_Functional }), + (Macro { str_GAMEPLAYATTRIBUTE_VALUE_GETTER, MT_Statement, MF_Functional }), + (Macro { str_GAMEPLAYATTRIBUTE_VALUE_SETTER, MT_Statement, MF_Functional }), + (Macro { str_GAMEPLAYATTRIBUTE_VALUE_INITTER, MT_Statement, MF_Functional }), + (Macro { str_LOCTEXT_NAMESPACE, MT_Statement, MF_Null }) + )); - // generate_AttributeSets(); - //generate_DevOptionsCache(); - //generate_HostWidgetController(); + // register_macros() + + generate_AttributeSets(); + generate_DevOptionsCache(); + // generate_HostWidgetController(); change_SBlueprintActionMenu_Construct(); change_EditorContentList(); - - gen::deinit(); }); } #undef LOCTEXT_NAMESPACE - diff --git a/Project/Source/GasaEditor/GasaGen/GasaGen_Common.h b/Project/Source/GasaEditor/GasaGen/GasaGen_Common.h index 35d98c9..1f8b7a3 100644 --- a/Project/Source/GasaEditor/GasaGen/GasaGen_Common.h +++ b/Project/Source/GasaEditor/GasaGen/GasaGen_Common.h @@ -17,54 +17,65 @@ using namespace gen; #define path_gasa_game path_module_gasa "Game/" #define path_gasa_ui path_module_gasa "UI/" -constexpr StrC str_DECLARE_CLASS = txt("DECLARE_CLASS("); -constexpr StrC str_DECLARE_DELEGATE_RetVal_OneParam = txt("DECLARE_DELEGATE_RetVal_OneParam("); -constexpr StrC str_DECLARE_DELEGATE_RetVal_ThreeParams = txt("DECLARE_DELEGATE_RetVal_ThreeParams("); -constexpr StrC str_DECLARE_DELEGATE_SixParams = txt("DECLARE_DELEGATE_SixParams("); -constexpr StrC str_DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam = txt("DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam("); -constexpr StrC str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_FiveParams = txt("DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_FiveParams("); -constexpr StrC str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_FourParams = txt("DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_FourParams("); -constexpr StrC str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_NineParams = txt("DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_NineParams("); -constexpr StrC str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_OneParam = txt("DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_OneParam("); -constexpr StrC str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_SevenParams = txt("DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_SevenParams("); -constexpr StrC str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_TwoParams = txt("DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_TwoParams("); -constexpr StrC str_DECLARE_EVENT_ThreeParams = txt("DECLARE_EVENT_ThreeParams("); -constexpr StrC str_DECLARE_EVENT_TwoParams = txt("DECLARE_EVENT_TwoParams("); -constexpr StrC str_DECLARE_FUNCTION = txt("DECLARE_FUNCTION("); -constexpr StrC str_DECLARE_LOG_CATEGORY_EXTERN = txt("DECLARE_LOG_CATEGORY_EXTERN("); -constexpr StrC str_DECLARE_MULTICAST_DELEGATE_OneParam = txt("DECLARE_MULTICAST_DELEGATE_OneParam("); -constexpr StrC str_DECLARE_MULTICAST_DELEGATE_ThreeParams = txt("DECLARE_MULTICAST_DELEGATE_ThreeParams("); -constexpr StrC str_DECLARE_MULTICAST_DELEGATE_TwoParams = txt("DECLARE_MULTICAST_DELEGATE_TwoParams("); -constexpr StrC str_DECLARE_TS_MULTICAST_DELEGATE_OneParam = txt("DECLARE_TS_MULTICAST_DELEGATE_OneParam("); -constexpr StrC str_DECLARE_TS_MULTICAST_DELEGATE_TwoParams = txt("DECLARE_TS_MULTICAST_DELEGATE_TwoParams("); -constexpr StrC str_DECLARE_TS_MULTICAST_DELEGATE_ThreeParams = txt("DECLARE_TS_MULTICAST_DELEGATE_ThreeParams("); -constexpr StrC str_DEFINE_ACTORDESC_TYPE = txt("DEFINE_ACTORDESC_TYPE("); -constexpr StrC str_DEFINE_DEFAULT_OBJECT_INITIALIZER_CONSTRUCTOR_CALL = txt("DEFINE_DEFAULT_OBJECT_INITIALIZER_CONSTRUCTOR_CALL("); -constexpr StrC str_ENUM_CLASS_FLAGS = txt("ENUM_CLASS_FLAGS("); -// constexpr StrC str_FORCEINLINE = txt("FORCEINLINE"); -constexpr StrC str_FORCEINLINE_DEBUGGABLE = txt("FORCEINLINE_DEBUGGABLE"); -constexpr StrC str_GENERATED_BODY = txt("GENERATED_BODY("); -constexpr StrC str_GENERATED_UCLASS_BODY = txt("GENERATED_UCLASS_BODY("); -constexpr StrC str_GENERATED_USTRUCT_BODY = txt("GENERATED_USTRUCT_BODY("); -constexpr StrC str_PRAGMA_DISABLE_DEPRECATION_WARNINGS = txt("PRAGMA_DISABLE_DEPRECATION_WARNINGS"); -constexpr StrC str_PRAGMA_ENABLE_DEPRECATION_WARNINGS = txt("PRAGMA_ENABLE_DEPRECATION_WARNINGS"); -constexpr StrC str_PROPERTY_BINDING_IMPLEMENTATION = txt("PROPERTY_BINDING_IMPLEMENTATION("); -constexpr StrC str_RESULT_DECL = txt("RESULT_DECL"); -constexpr StrC str_SLATE_BEGIN_ARGS = txt("SLATE_BEGIN_ARGS("); -constexpr StrC str_SLATE_END_ARGS = txt("SLATE_END_ARGS("); -constexpr StrC str_TEXT = txt("TEXT("); -constexpr StrC str_UCLASS = txt("UCLASS("); -constexpr StrC str_UENUM = txt("UENUM("); -constexpr StrC str_UFUNCTION = txt("UFUNCTION("); -constexpr StrC str_UMETA = txt("UMETA("); -constexpr StrC str_UPARAM = txt("UPARAM("); -constexpr StrC str_UPROPERTY = txt("UPROPERTY("); -constexpr StrC str_USTRUCT = txt("USTRUCT("); -constexpr StrC str_UE_REQUIRES = txt("UE_REQUIRES("); +constexpr Str str_DECLARE_CLASS = txt("DECLARE_CLASS"); +constexpr Str str_DECLARE_DELEGATE_RetVal_OneParam = txt("DECLARE_DELEGATE_RetVal_OneParam"); +constexpr Str str_DECLARE_DELEGATE_RetVal_ThreeParams = txt("DECLARE_DELEGATE_RetVal_ThreeParams"); +constexpr Str str_DECLARE_DELEGATE_SixParams = txt("DECLARE_DELEGATE_SixParams"); +constexpr Str str_DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam = txt("DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam"); +constexpr Str str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_FiveParams = txt("DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_FiveParams"); +constexpr Str str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_FourParams = txt("DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_FourParams"); +constexpr Str str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_NineParams = txt("DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_NineParams"); +constexpr Str str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_OneParam = txt("DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_OneParam"); +constexpr Str str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_SevenParams = txt("DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_SevenParams"); +constexpr Str str_DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_TwoParams = txt("DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_TwoParams"); +constexpr Str str_DECLARE_EVENT_ThreeParams = txt("DECLARE_EVENT_ThreeParams"); +constexpr Str str_DECLARE_EVENT_TwoParams = txt("DECLARE_EVENT_TwoParams"); +constexpr Str str_DECLARE_FUNCTION = txt("DECLARE_FUNCTION"); +constexpr Str str_DECLARE_LOG_CATEGORY_EXTERN = txt("DECLARE_LOG_CATEGORY_EXTERN"); +constexpr Str str_DECLARE_MULTICAST_DELEGATE_OneParam = txt("DECLARE_MULTICAST_DELEGATE_OneParam"); +constexpr Str str_DECLARE_MULTICAST_DELEGATE_ThreeParams = txt("DECLARE_MULTICAST_DELEGATE_ThreeParams"); +constexpr Str str_DECLARE_MULTICAST_DELEGATE_TwoParams = txt("DECLARE_MULTICAST_DELEGATE_TwoParams"); +constexpr Str str_DECLARE_TS_MULTICAST_DELEGATE_OneParam = txt("DECLARE_TS_MULTICAST_DELEGATE_OneParam"); +constexpr Str str_DECLARE_TS_MULTICAST_DELEGATE_TwoParams = txt("DECLARE_TS_MULTICAST_DELEGATE_TwoParams"); +constexpr Str str_DECLARE_TS_MULTICAST_DELEGATE_ThreeParams = txt("DECLARE_TS_MULTICAST_DELEGATE_ThreeParams"); +constexpr Str str_DEFINE_ACTORDESC_TYPE = txt("DEFINE_ACTORDESC_TYPE"); +constexpr Str str_DEFINE_DEFAULT_OBJECT_INITIALIZER_CONSTRUCTOR_CALL = txt("DEFINE_DEFAULT_OBJECT_INITIALIZER_CONSTRUCTOR_CALL"); +constexpr Str str_ENUM_CLASS_FLAGS = txt("ENUM_CLASS_FLAGS"); +constexpr Str str_GENERATED_BODY = txt("GENERATED_BODY"); +constexpr Str str_GENERATED_UCLASS_BODY = txt("GENERATED_UCLASS_BODY"); +constexpr Str str_GENERATED_USTRUCT_BODY = txt("GENERATED_USTRUCT_BODY"); +constexpr Str str_PRAGMA_DISABLE_DEPRECATION_WARNINGS = txt("PRAGMA_DISABLE_DEPRECATION_WARNINGS"); +constexpr Str str_PRAGMA_ENABLE_DEPRECATION_WARNINGS = txt("PRAGMA_ENABLE_DEPRECATION_WARNINGS"); +constexpr Str str_PROPERTY_BINDING_IMPLEMENTATION = txt("PROPERTY_BINDING_IMPLEMENTATION"); +constexpr Str str_RESULT_DECL = txt("RESULT_DECL"); +constexpr Str str_SLATE_BEGIN_ARGS = txt("SLATE_BEGIN_ARGS"); +constexpr Str str_SLATE_END_ARGS = txt("SLATE_END_ARGS"); +constexpr Str str_TEXT = txt("TEXT"); +constexpr Str str_UCLASS = txt("UCLASS"); +constexpr Str str_UENUM = txt("UENUM"); +constexpr Str str_UFUNCTION = txt("UFUNCTION"); +constexpr Str str_UMETA = txt("UMETA"); +constexpr Str str_UPARAM = txt("UPARAM"); +constexpr Str str_UPROPERTY = txt("UPROPERTY"); +constexpr Str str_USTRUCT = txt("USTRUCT"); +constexpr Str str_UE_REQUIRES = txt("UE_REQUIRES"); +constexpr Str str_UE_DEPRECATED = txt("UE_DEPRECATED"); +constexpr Str str_ACTOR_HAS_LABELS = txt("ACTOR_HAS_LABELS"); +constexpr Str str_HIDE_ACTOR_TRANSFORM_FUNCTIONS = txt("HIDE_ACTOR_TRANSFORM_FUNCTIONS"); +constexpr Str str_SCENECOMPONENT_QUAT_TOLERANCE = txt("SCENECOMPONENT_QUAT_TOLERANCE"); +constexpr Str str_SCENECOMPONENT_ROTATOR_TOLERANCE = txt("SCENECOMPONENT_ROTATOR_TOLERANCE"); +constexpr Str str_GAMEPLAYATTRIBUTE_REPNOTIFY = txt("GAMEPLAYATTRIBUTE_REPNOTIFY"); +constexpr Str str_GAMEPLAYATTRIBUTE_PROPERTY_GETTER = txt("GAMEPLAYATTRIBUTE_PROPERTY_GETTER"); +constexpr Str str_GAMEPLAYATTRIBUTE_VALUE_GETTER = txt("GAMEPLAYATTRIBUTE_VALUE_GETTER"); +constexpr Str str_GAMEPLAYATTRIBUTE_VALUE_SETTER = txt("GAMEPLAYATTRIBUTE_VALUE_SETTER"); +constexpr Str str_GAMEPLAYATTRIBUTE_VALUE_INITTER = txt("GAMEPLAYATTRIBUTE_VALUE_INITTER"); +constexpr Str str_LOCTEXT_NAMESPACE = txt("LOCTEXT_NAMESPACE"); + +constexpr Str str_GASA_API = txt("GASA_API"); #pragma region Globals -extern String Project_Path; -extern String Root_Path; +extern Str Project_Path; +extern Str Root_Path; // These Code objects are created before anything else after gencpp does its initializatioon extern Code UHT_GENERATED_BODY; @@ -72,24 +83,26 @@ extern Code UHT_UCLASS; extern Code UHT_UPROPERTY; extern Code UHT_USTRUCT; extern Code UModule_GASA_API; + +extern Context gen_ctx; #pragma endregion Globals inline CodeBody parse_file( char const* path ) { - String - resolved_path = String::make(GlobalAllocator, StrC(Project_Path)); + StrBuilder + resolved_path = StrBuilder::make(gen_ctx.Allocator_Temp, Project_Path); resolved_path.append(path); - FileContents content = file_read_contents( GlobalAllocator, true, resolved_path ); - CodeBody code = parse_global_body( StrC { content.size, (char const*)content.data }); + FileContents content = file_read_contents( gen_ctx.Allocator_Temp, true, resolved_path ); + CodeBody code = parse_global_body( Str { (char const*)content.data, content.size }); return code; } // Automatically handles resolving project path inline -Builder builder_open(char const* path) { - String - resolved_path = String::make(GlobalAllocator, StrC(Project_Path)); +Builder gasa_builder_open(char const* path) { + StrBuilder + resolved_path = StrBuilder::make(gen_ctx.Allocator_Temp, Project_Path); resolved_path.append(path); return Builder::open( resolved_path ); } @@ -100,13 +113,13 @@ Builder builder_open(char const* path) { inline void format_file( char const* path, bool relative_path = true ) { - String - resolved_path = String::make_reserve(GlobalAllocator, Project_Path.length()); + StrBuilder + resolved_path = StrBuilder::make_reserve(gen_ctx.Allocator_Temp, Project_Path.Len); if (relative_path) - resolved_path.append(StrC(Project_Path)); + resolved_path.append(Project_Path); resolved_path.append(path); - String style_arg = String::make(GlobalAllocator, txt("-style=file:")); + StrBuilder style_arg = StrBuilder::make(gen_ctx.Allocator_Temp, txt("-style=file:")); style_arg.append(Root_Path); style_arg.append("/scripts/.clang-format "); @@ -114,7 +127,7 @@ void format_file( char const* path, bool relative_path = true ) #define clang_format "clang-format " #define cf_format_inplace "-i " #define cf_verbose "-verbose " - String command = String::make( GlobalAllocator, clang_format ); + StrBuilder command = StrBuilder::make( gen_ctx.Allocator_Temp, clang_format ); command.append( cf_format_inplace ); command.append( cf_verbose ); command.append( style_arg ); @@ -129,19 +142,19 @@ void format_file( char const* path, bool relative_path = true ) } FORCEINLINE -String to_string( FString ue_string ) { +Str to_string( FString ue_string ) { char const* ansi_str = TCHAR_TO_ANSI(*ue_string); - return String::make_length(GlobalAllocator, ansi_str, ue_string.Len()); + return StrBuilder::make_length(gen_ctx.Allocator_Temp, ansi_str, ue_string.Len()).to_str(); } FORCEINLINE -String to_string( FName ue_fname ) { +Str to_string( FName ue_fname ) { char const* ansi_str = TCHAR_TO_ANSI(*ue_fname.ToString()); - return String::make_length(GlobalAllocator, ansi_str, ue_fname.GetStringLength()); + return StrBuilder::make_length(gen_ctx.Allocator_Temp, ansi_str, ue_fname.GetStringLength()).to_str(); } FORCEINLINE -FString to_fstring( String string ) +FString to_fstring( Str string ) { - return FString::ConstructFromPtrSize( string.Data, string.length() ); + return FString::ConstructFromPtrSize( string.Ptr, string.Len ); } diff --git a/Project/Source/GasaEditor/GasaGen/gencpp/gen.builder.cpp b/Project/Source/GasaEditor/GasaGen/gencpp/gen.builder.cpp index 1cdcac5..6bbdee2 100644 --- a/Project/Source/GasaEditor/GasaGen/gencpp/gen.builder.cpp +++ b/Project/Source/GasaEditor/GasaGen/gencpp/gen.builder.cpp @@ -39,7 +39,9 @@ Builder builder_open( char const* path ) return result; } - result.Buffer = strbuilder_make_reserve( _ctx->Allocator_Temp, _ctx->InitSize_BuilderBuffer ); + Context* ctx = get_context(); + GEN_ASSERT_NOT_NULL(ctx); + result.Buffer = strbuilder_make_reserve( ctx->Allocator_Temp, ctx->InitSize_BuilderBuffer ); // log_fmt("$Builder - Opened file: %s\n", result.File.filename ); return result; diff --git a/Project/Source/GasaEditor/GasaGen/gencpp/gen.builder.hpp b/Project/Source/GasaEditor/GasaGen/gencpp/gen.builder.hpp index 60d8a08..02d2589 100644 --- a/Project/Source/GasaEditor/GasaGen/gencpp/gen.builder.hpp +++ b/Project/Source/GasaEditor/GasaGen/gencpp/gen.builder.hpp @@ -37,13 +37,14 @@ Builder builder_open ( char const* path ); void builder_pad_lines ( Builder* builder, s32 num ); void builder_print ( Builder* builder, Code code ); void builder_print_fmt_va( Builder* builder, char const* fmt, va_list va ); -void builder_print_fmt ( Builder* builder, char const* fmt, ... ) { +void builder_write ( Builder* builder ); + +FORCEINLINE void builder_print_fmt ( Builder* builder, char const* fmt, ... ) { va_list va; va_start( va, fmt ); builder_print_fmt_va( builder, fmt, va ); va_end( va ); } -void builder_write( Builder* builder ); struct Builder { @@ -68,10 +69,10 @@ struct Builder }; #if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP -void builder_pad_lines( Builder& builder, s32 num ) { return builder_pad_lines(& builder, num); } -void builder_print ( Builder& builder, Code code ) { return builder_print(& builder, code); } -void builder_write ( Builder& builder ) { return builder_write(& builder ); } -void builder_print_fmt( Builder& builder, char const* fmt, ...) { +FORCEINLINE void builder_pad_lines( Builder& builder, s32 num ) { return builder_pad_lines(& builder, num); } +FORCEINLINE void builder_print ( Builder& builder, Code code ) { return builder_print(& builder, code); } +FORCEINLINE void builder_write ( Builder& builder ) { return builder_write(& builder ); } +FORCEINLINE void builder_print_fmt( Builder& builder, char const* fmt, ...) { va_list va; va_start( va, fmt ); builder_print_fmt_va( & builder, fmt, va ); diff --git a/Project/Source/GasaEditor/GasaGen/gencpp/gen.cpp b/Project/Source/GasaEditor/GasaGen/gencpp/gen.cpp index b5e9341..fdd2e3b 100644 --- a/Project/Source/GasaEditor/GasaGen/gencpp/gen.cpp +++ b/Project/Source/GasaEditor/GasaGen/gencpp/gen.cpp @@ -3403,6 +3403,10 @@ void deinit(Context* ctx) -- context_counter; } +Context* get_context() { + return _ctx; +} + void reset(Context* ctx) { s32 index = 0; @@ -4809,7 +4813,7 @@ CodeUsing def_using_namespace( Str name ) CodeVar def_variable( CodeTypename type, Str name, Opts_def_variable p ) { - if ( ! name_check( def_variable, name ) || null_check( def_variable, type ) ) { + if ( ! name_check( def_variable, name ) || ! null_check( def_variable, type ) ) { GEN_DEBUG_TRAP(); return InvalidCode; } @@ -5786,7 +5790,7 @@ s32 lex_preprocessor_define( LexContext* ctx ) array_append( _ctx->Lexer_Tokens, opening_paren ); move_forward(); - Token last_parameter; + Token last_parameter = {}; // We need to tokenize the define's arguments now: while( ctx->left && * ctx->scanner != ')') { @@ -9520,7 +9524,40 @@ Code parse_operator_function_or_variable( bool expects_function, CodeAttributes // Example : // idx +1 +2 bool detected_comma = _ctx->parser.Tokens.Arr[ _ctx->parser.Tokens.Idx + 2 ].Type == Tok_Comma; - if ( detected_capture && ! detected_comma ) + + b32 detected_non_varadic_unpaired_param = detected_comma && nexttok.Type != Tok_Varadic_Argument; + if (! detected_non_varadic_unpaired_param && nexttok.Type == Tok_Preprocess_Macro_Expr) for( s32 break_scope = 0; break_scope == 0; ++ break_scope) + { + Macro* macro = lookup_macro( nexttok.Text ); + if (macro == nullptr || ! macro_is_functional(* macro)) + break; + + // ( ( + // Idx +1 +2 + s32 idx = _ctx->parser.Tokens.Idx + 1; + s32 level = 0; + + // Find end of the token expression + for ( ; idx < array_num(_ctx->parser.Tokens.Arr); idx++ ) + { + Token tok = _ctx->parser.Tokens.Arr[ idx ]; + + if ( tok.Type == Tok_Capture_Start ) + level++; + else if ( tok.Type == Tok_Capture_End && level > 0 ) + level--; + if (level == 0 && tok.Type == Tok_Capture_End) + break; + } + ++ idx; // Will incremnt to possible comma position + + if ( _ctx->parser.Tokens.Arr[ idx ].Type != Tok_Comma ) + break; + + detected_non_varadic_unpaired_param = true; + } + + if ( detected_capture && ! detected_non_varadic_unpaired_param ) { // Dealing with a function result = cast(Code, parse_function_after_name( ModuleFlag_None, attributes, specifiers, type, name )); @@ -9539,7 +9576,7 @@ Code parse_operator_function_or_variable( bool expects_function, CodeAttributes } } - parser_pop(& _ctx->parser); + parser_pop(& _ctx->parser); return result; } @@ -10032,7 +10069,7 @@ Code parse_simple_preprocess( TokType which ) || str_contains(calling_proc, txt("parse_class_struct_body")) ) { - if (peektok.Type == Tok_Statement_End) + if (left && peektok.Type == Tok_Statement_End) { Token stmt_end = currtok; eat( Tok_Statement_End ); @@ -12045,7 +12082,6 @@ CodeTypedef parser_parse_typedef() // valid_macro |= macro && macro_expects_body(* macro)); // } - Code macro; if ( valid_macro ) #endif { @@ -12893,6 +12929,12 @@ CodeVar parse_variable( Str def ) #undef parser_use_parenthesis #undef parser_strip_formatting_dont_preserve_newlines +#pragma endregion Parsing + + +#pragma region Untyped + + ssize token_fmt_va( char* buf, usize buf_size, s32 num_tokens, va_list va ) { char const* buf_begin = buf; @@ -13067,8 +13109,7 @@ Code untyped_token_fmt( s32 num_tokens, char const* fmt, ... ) return result; } - -#pragma endregion Parsing +#pragma endregion #pragma endregion Interface diff --git a/Project/Source/GasaEditor/GasaGen/gencpp/gen.dep.cpp b/Project/Source/GasaEditor/GasaGen/gencpp/gen.dep.cpp index d1a5e57..adc9d7b 100644 --- a/Project/Source/GasaEditor/GasaGen/gencpp/gen.dep.cpp +++ b/Project/Source/GasaEditor/GasaGen/gencpp/gen.dep.cpp @@ -1384,25 +1384,25 @@ void* arena_allocator_proc( void* allocator_data, AllocType type, ssize size, ss switch ( type ) { case EAllocation_ALLOC : + { + void* end = pointer_add( arena->PhysicalStart, arena->TotalUsed ); + ssize total_size = align_forward_s64( size, alignment ); + + // NOTE: Out of memory + if ( arena->TotalUsed + total_size > (ssize) arena->TotalSize ) { - void* end = pointer_add( arena->PhysicalStart, arena->TotalUsed ); - ssize total_size = align_forward_s64( size, alignment ); - - // NOTE: Out of memory - if ( arena->TotalUsed + total_size > (ssize) arena->TotalSize ) - { - // zpl__printf_err("%s", "Arena out of memory\n"); - GEN_FATAL("Arena out of memory! (Possibly could not fit for the largest size Arena!!)"); - return nullptr; - } - - ptr = align_forward( end, alignment ); - arena->TotalUsed += total_size; - - if ( flags & ALLOCATOR_FLAG_CLEAR_TO_ZERO ) - zero_size( ptr, size ); + // zpl__printf_err("%s", "Arena out of memory\n"); + GEN_FATAL("Arena out of memory! (Possibly could not fit for the largest size Arena!!)"); } - break; + + + ptr = align_forward( end, alignment ); + arena->TotalUsed += total_size; + + if ( flags & ALLOCATOR_FLAG_CLEAR_TO_ZERO ) + zero_size( ptr, size ); + } + break; case EAllocation_FREE : // NOTE: Free all at once @@ -2434,6 +2434,1118 @@ FileOperations const memory_file_operations = { _memory_file_read, _memory_file_ #pragma endregion Timing +#pragma region ADT + +#define _adt_fprintf( s_, fmt_, ... ) \ + do \ + { \ + if ( c_str_fmt_file( s_, fmt_, ##__VA_ARGS__ ) < 0 ) \ + return EADT_ERROR_OUT_OF_MEMORY; \ + } while ( 0 ) + +u8 adt_make_branch( ADT_Node* node, AllocatorInfo backing, char const* name, b32 is_array ) +{ + ADT_Type type = EADT_TYPE_OBJECT; + if ( is_array ) + type = EADT_TYPE_ARRAY; + + ADT_Node* parent = node->parent; + zero_item( node ); + + node->type = type; + node->name = name; + node->parent = parent; + node->nodes = array_init(ADT_Node, backing ); + + if ( ! node->nodes ) + return EADT_ERROR_OUT_OF_MEMORY; + + return 0; +} + +u8 adt_destroy_branch( ADT_Node* node ) +{ + GEN_ASSERT_NOT_NULL( node ); + if ( ( node->type == EADT_TYPE_OBJECT || node->type == EADT_TYPE_ARRAY ) && node->nodes ) + { + for ( ssize i = 0; i < scast(ssize, array_num(node->nodes)); ++i ) + { + adt_destroy_branch( node->nodes + i ); + } + + array_free(node->nodes); + } + return 0; +} + +u8 adt_make_leaf( ADT_Node* node, char const* name, ADT_Type type ) +{ + GEN_ASSERT( type != EADT_TYPE_OBJECT && type != EADT_TYPE_ARRAY ); + + ADT_Node* parent = node->parent; + zero_item( node ); + + node->type = type; + node->name = name; + node->parent = parent; + return 0; +} + +ADT_Node* adt_find( ADT_Node* node, char const* name, b32 deep_search ) +{ + if ( node->type != EADT_TYPE_OBJECT ) + { + return NULL; + } + + for ( ssize i = 0; i < scast(ssize, array_num(node->nodes)); i++ ) + { + if ( ! c_str_compare( node->nodes[ i ].name, name ) ) + { + return ( node->nodes + i ); + } + } + + if ( deep_search ) + { + for ( ssize i = 0; i < scast(ssize, array_num(node->nodes)); i++ ) + { + ADT_Node* res = adt_find( node->nodes + i, name, deep_search ); + + if ( res != NULL ) + return res; + } + } + + return NULL; +} + +internal ADT_Node* _adt_get_value( ADT_Node* node, char const* value ) +{ + switch ( node->type ) + { + case EADT_TYPE_MULTISTRING : + case EADT_TYPE_STRING : + { + if ( node->string && ! c_str_compare( node->string, value ) ) + { + return node; + } + } + break; + case EADT_TYPE_INTEGER : + case EADT_TYPE_REAL : + { + char back[ 4096 ] = { 0 }; + FileInfo tmp; + + /* allocate a file descriptor for a memory-mapped number to string conversion, input source buffer is not cloned, however. */ + file_stream_open( &tmp, heap(), ( u8* )back, size_of( back ), EFileStream_WRITABLE ); + adt_print_number( &tmp, node ); + + ssize fsize = 0; + u8* buf = file_stream_buf( &tmp, &fsize ); + + if ( ! c_str_compare( ( char const* )buf, value ) ) + { + file_close( &tmp ); + return node; + } + + file_close( &tmp ); + } + break; + default : + break; /* node doesn't support value based lookup */ + } + + return NULL; +} + +internal ADT_Node* _adt_get_field( ADT_Node* node, char* name, char* value ) +{ + for ( ssize i = 0; i < scast(ssize, array_num(node->nodes)); i++ ) + { + if ( ! c_str_compare( node->nodes[ i ].name, name ) ) + { + ADT_Node* child = &node->nodes[ i ]; + if ( _adt_get_value( child, value ) ) + { + return node; /* this object does contain a field of a specified value! */ + } + } + } + + return NULL; +} + +ADT_Node* adt_query( ADT_Node* node, char const* uri ) +{ + GEN_ASSERT_NOT_NULL( uri ); + + if ( *uri == '/' ) + { + uri++; + } + + if ( *uri == 0 ) + { + return node; + } + + if ( ! node || ( node->type != EADT_TYPE_OBJECT && node->type != EADT_TYPE_ARRAY ) ) + { + return NULL; + } + +#if defined EADT_URI_DEBUG || 0 + c_str_fmt_out( "uri: %s\n", uri ); +#endif + + char * p = ( char* )uri, *b = p, *e = p; + ADT_Node* found_node = NULL; + + b = p; + p = e = ( char* )c_str_skip( p, '/' ); + char* buf = c_str_fmt_buf( "%.*s", ( int )( e - b ), b ); + + /* handle field value lookup */ + if ( *b == '[' ) + { + char *l_p = buf + 1, *l_b = l_p, *l_e = l_p, *l_b2 = l_p, *l_e2 = l_p; + l_e = ( char* )c_str_skip( l_p, '=' ); + l_e2 = ( char* )c_str_skip( l_p, ']' ); + + if ( ( ! *l_e && node->type != EADT_TYPE_ARRAY ) || ! *l_e2 ) + { + GEN_ASSERT_MSG( 0, "Invalid field value lookup" ); + return NULL; + } + + *l_e2 = 0; + + /* [field=value] */ + if ( *l_e ) + { + *l_e = 0; + l_b2 = l_e + 1; + + /* run a value comparison against our own fields */ + if ( node->type == EADT_TYPE_OBJECT ) + { + found_node = _adt_get_field( node, l_b, l_b2 ); + } + + /* run a value comparison against any child that is an object node */ + else if ( node->type == EADT_TYPE_ARRAY ) + { + for ( ssize i = 0; i < scast(ssize, array_num(node->nodes)); i++ ) + { + ADT_Node* child = &node->nodes[ i ]; + if ( child->type != EADT_TYPE_OBJECT ) + { + continue; + } + + found_node = _adt_get_field( child, l_b, l_b2 ); + + if ( found_node ) + break; + } + } + } + /* [value] */ + else + { + for ( ssize i = 0; i < scast(ssize, array_num(node->nodes)); i++ ) + { + ADT_Node* child = &node->nodes[ i ]; + if ( _adt_get_value( child, l_b2 ) ) + { + found_node = child; + break; /* we found a matching value in array, ignore the rest of it */ + } + } + } + + /* go deeper if uri continues */ + if ( *e ) + { + return adt_query( found_node, e + 1 ); + } + } + /* handle field name lookup */ + else if ( node->type == EADT_TYPE_OBJECT ) + { + found_node = adt_find( node, buf, false ); + + /* go deeper if uri continues */ + if ( *e ) + { + return adt_query( found_node, e + 1 ); + } + } + /* handle array index lookup */ + else + { + ssize idx = ( ssize )c_str_to_i64( buf, NULL, 10 ); + if ( idx >= 0 && idx < scast(ssize, array_num(node->nodes)) ) + { + found_node = &node->nodes[ idx ]; + + /* go deeper if uri continues */ + if ( *e ) + { + return adt_query( found_node, e + 1 ); + } + } + } + + return found_node; +} + +ADT_Node* adt_alloc_at( ADT_Node* parent, ssize index ) +{ + if ( ! parent || ( parent->type != EADT_TYPE_OBJECT && parent->type != EADT_TYPE_ARRAY ) ) + { + return NULL; + } + + if ( ! parent->nodes ) + return NULL; + + if ( index < 0 || index > scast(ssize, array_num(parent->nodes)) ) + return NULL; + + ADT_Node o = { 0 }; + o.parent = parent; + if ( ! array_append_at( parent->nodes, o, index ) ) + return NULL; + + ADT_Node* node = & parent->nodes[index]; + return node; +} + +ADT_Node* adt_alloc( ADT_Node* parent ) +{ + if ( ! parent || ( parent->type != EADT_TYPE_OBJECT && parent->type != EADT_TYPE_ARRAY ) ) + { + return NULL; + } + + if ( ! parent->nodes ) + return NULL; + + return adt_alloc_at( parent, array_num(parent->nodes) ); +} + +b8 adt_set_obj( ADT_Node* obj, char const* name, AllocatorInfo backing ) +{ + return adt_make_branch( obj, backing, name, 0 ); +} + +b8 adt_set_arr( ADT_Node* obj, char const* name, AllocatorInfo backing ) +{ + return adt_make_branch( obj, backing, name, 1 ); +} + +b8 adt_set_str( ADT_Node* obj, char const* name, char const* value ) +{ + adt_make_leaf( obj, name, EADT_TYPE_STRING ); + obj->string = value; + return true; +} + +b8 adt_set_flt( ADT_Node* obj, char const* name, f64 value ) +{ + adt_make_leaf( obj, name, EADT_TYPE_REAL ); + obj->real = value; + return true; +} + +b8 adt_set_int( ADT_Node* obj, char const* name, s64 value ) +{ + adt_make_leaf( obj, name, EADT_TYPE_INTEGER ); + obj->integer = value; + return true; +} + +ADT_Node* adt_move_node_at( ADT_Node* node, ADT_Node* new_parent, ssize index ) +{ + GEN_ASSERT_NOT_NULL( node ); + GEN_ASSERT_NOT_NULL( new_parent ); + ADT_Node* old_parent = node->parent; + ADT_Node* new_node = adt_alloc_at( new_parent, index ); + *new_node = *node; + new_node->parent = new_parent; + if ( old_parent ) + { + adt_remove_node( node ); + } + return new_node; +} + +ADT_Node* adt_move_node( ADT_Node* node, ADT_Node* new_parent ) +{ + GEN_ASSERT_NOT_NULL( node ); + GEN_ASSERT_NOT_NULL( new_parent ); + GEN_ASSERT( new_parent->type == EADT_TYPE_ARRAY || new_parent->type == EADT_TYPE_OBJECT ); + return adt_move_node_at( node, new_parent, array_num(new_parent->nodes) ); +} + +void adt_swap_nodes( ADT_Node* node, ADT_Node* other_node ) +{ + GEN_ASSERT_NOT_NULL( node ); + GEN_ASSERT_NOT_NULL( other_node ); + ADT_Node* parent = node->parent; + ADT_Node* other_parent = other_node->parent; + ssize index = ( pointer_diff( parent->nodes, node ) / size_of( ADT_Node ) ); + ssize index2 = ( pointer_diff( other_parent->nodes, other_node ) / size_of( ADT_Node ) ); + ADT_Node temp = parent->nodes[ index ]; + temp.parent = other_parent; + other_parent->nodes[ index2 ].parent = parent; + parent->nodes[ index ] = other_parent->nodes[ index2 ]; + other_parent->nodes[ index2 ] = temp; +} + +void adt_remove_node( ADT_Node* node ) +{ + GEN_ASSERT_NOT_NULL( node ); + GEN_ASSERT_NOT_NULL( node->parent ); + ADT_Node* parent = node->parent; + ssize index = ( pointer_diff( parent->nodes, node ) / size_of( ADT_Node ) ); + array_remove_at( parent->nodes, index ); +} + +ADT_Node* adt_append_obj( ADT_Node* parent, char const* name ) +{ + ADT_Node* o = adt_alloc( parent ); + if ( ! o ) + return NULL; + if ( adt_set_obj( o, name, array_get_header(parent->nodes)->Allocator ) ) + { + adt_remove_node( o ); + return NULL; + } + return o; +} + +ADT_Node* adt_append_arr( ADT_Node* parent, char const* name ) +{ + ADT_Node* o = adt_alloc( parent ); + if ( ! o ) + return NULL; + + ArrayHeader* node_header = array_get_header(parent->nodes); + if ( adt_set_arr( o, name, node_header->Allocator ) ) + { + adt_remove_node( o ); + return NULL; + } + return o; +} + +ADT_Node* adt_append_str( ADT_Node* parent, char const* name, char const* value ) +{ + ADT_Node* o = adt_alloc( parent ); + if ( ! o ) + return NULL; + adt_set_str( o, name, value ); + return o; +} + +ADT_Node* adt_append_flt( ADT_Node* parent, char const* name, f64 value ) +{ + ADT_Node* o = adt_alloc( parent ); + if ( ! o ) + return NULL; + adt_set_flt( o, name, value ); + return o; +} + +ADT_Node* adt_append_int( ADT_Node* parent, char const* name, s64 value ) +{ + ADT_Node* o = adt_alloc( parent ); + if ( ! o ) + return NULL; + adt_set_int( o, name, value ); + return o; +} + +/* parser helpers */ +char* adt_parse_number_strict( ADT_Node* node, char* base_str ) +{ + GEN_ASSERT_NOT_NULL( node ); + GEN_ASSERT_NOT_NULL( base_str ); + char *p = base_str, *e = p; + + while ( *e ) + ++e; + + while ( *p && ( char_first_occurence( "eE.+-", *p ) || char_is_hex_digit( *p ) ) ) + { + ++p; + } + + if ( p >= e ) + { + return adt_parse_number( node, base_str ); + } + + return base_str; +} + +char* adt_parse_number( ADT_Node* node, char* base_str ) +{ + GEN_ASSERT_NOT_NULL( node ); + GEN_ASSERT_NOT_NULL( base_str ); + char *p = base_str, *e = p; + + s32 base = 0; + s32 base2 = 0; + u8 base2_offset = 0; + s8 exp = 0, orig_exp = 0; + u8 neg_zero = 0; + u8 lead_digit = 0; + ADT_Type node_type = EADT_TYPE_UNINITIALISED; + u8 node_props = 0; + + /* skip false positives and special cases */ + if ( ! ! char_first_occurence( "eE", *p ) || ( ! ! char_first_occurence( ".+-", *p ) && ! char_is_hex_digit( *( p + 1 ) ) && *( p + 1 ) != '.' ) ) + { + return ++base_str; + } + + node_type = EADT_TYPE_INTEGER; + neg_zero = false; + + ssize ib = 0; + char buf[ 48 ] = { 0 }; + + if ( *e == '+' ) + ++e; + else if ( *e == '-' ) + { + buf[ ib++ ] = *e++; + } + + if ( *e == '.' ) + { + node_type = EADT_TYPE_REAL; + node_props = EADT_PROPS_IS_PARSED_REAL; + lead_digit = false; + buf[ ib++ ] = '0'; + do + { + buf[ ib++ ] = *e; + } while ( char_is_digit( *++e ) ); + } + else + { + if ( ! c_str_compare_len( e, "0x", 2 ) || ! c_str_compare_len( e, "0X", 2 ) ) + { + node_props = EADT_PROPS_IS_HEX; + } + + /* bail if ZPL_ADT_PROPS_IS_HEX is unset but we get 'x' on input */ + if ( char_to_lower( *e ) == 'x' && ( node_props != EADT_PROPS_IS_HEX ) ) + { + return ++base_str; + } + + while ( char_is_hex_digit( *e ) || char_to_lower( *e ) == 'x' ) + { + buf[ ib++ ] = *e++; + } + + if ( *e == '.' ) + { + node_type = EADT_TYPE_REAL; + lead_digit = true; + u32 step = 0; + + do + { + buf[ ib++ ] = *e; + ++step; + } while ( char_is_digit( *++e ) ); + + if ( step < 2 ) + { + buf[ ib++ ] = '0'; + } + } + } + + /* check if we have a dot here, this is a false positive (IP address, ...) */ + if ( *e == '.' ) + { + return ++base_str; + } + + f32 eb = 10; + char expbuf[ 6 ] = { 0 }; + ssize expi = 0; + + if ( *e && ! ! char_first_occurence( "eE", *e ) ) + { + ++e; + if ( *e == '+' || *e == '-' || char_is_digit( *e ) ) + { + if ( *e == '-' ) + { + eb = 0.1f; + } + if ( ! char_is_digit( *e ) ) + { + ++e; + } + while ( char_is_digit( *e ) ) + { + expbuf[ expi++ ] = *e++; + } + } + + orig_exp = exp = ( u8 )c_str_to_i64( expbuf, NULL, 10 ); + } + + if ( node_type == EADT_TYPE_INTEGER ) + { + node->integer = c_str_to_i64( buf, 0, 0 ); +#ifndef GEN_PARSER_DISABLE_ANALYSIS + /* special case: negative zero */ + if ( node->integer == 0 && buf[ 0 ] == '-' ) + { + neg_zero = true; + } +#endif + while ( orig_exp-- > 0 ) + { + node->integer *= ( s64 )eb; + } + } + else + { + node->real = c_str_to_f64( buf, 0 ); + +#ifndef GEN_PARSER_DISABLE_ANALYSIS + char *q = buf, *base_string = q, *base_string2 = q; + base_string = ccast( char*, c_str_skip( base_string, '.' )); + *base_string = '\0'; + base_string2 = base_string + 1; + char* base_strbuilder_off = base_string2; + while ( *base_strbuilder_off++ == '0' ) + base2_offset++; + + base = ( s32 )c_str_to_i64( q, 0, 0 ); + base2 = ( s32 )c_str_to_i64( base_string2, 0, 0 ); + if ( exp ) + { + exp = exp * ( ! ( eb == 10.0f ) ? -1 : 1 ); + node_props = EADT_PROPS_IS_EXP; + } + + /* special case: negative zero */ + if ( base == 0 && buf[ 0 ] == '-' ) + { + neg_zero = true; + } +#endif + while ( orig_exp-- > 0 ) + { + node->real *= eb; + } + } + + node->type = node_type; + node->props = node_props; + +#ifndef GEN_PARSER_DISABLE_ANALYSIS + node->base = base; + node->base2 = base2; + node->base2_offset = base2_offset; + node->exp = exp; + node->neg_zero = neg_zero; + node->lead_digit = lead_digit; +#else + unused( base ); + unused( base2 ); + unused( base2_offset ); + unused( exp ); + unused( neg_zero ); + unused( lead_digit ); +#endif + return e; +} + +ADT_Error adt_print_number( FileInfo* file, ADT_Node* node ) +{ + GEN_ASSERT_NOT_NULL( file ); + GEN_ASSERT_NOT_NULL( node ); + if ( node->type != EADT_TYPE_INTEGER && node->type != EADT_TYPE_REAL ) + { + return EADT_ERROR_INVALID_TYPE; + } + +#ifndef GEN_PARSER_DISABLE_ANALYSIS + if ( node->neg_zero ) + { + _adt_fprintf( file, "-" ); + } +#endif + + switch ( node->type ) + { + case EADT_TYPE_INTEGER : + { + if ( node->props == EADT_PROPS_IS_HEX ) + { + _adt_fprintf( file, "0x%llx", ( long long )node->integer ); + } + else + { + _adt_fprintf( file, "%lld", ( long long )node->integer ); + } + } + break; + + case EADT_TYPE_REAL : + { + if ( node->props == EADT_PROPS_NAN ) + { + _adt_fprintf( file, "NaN" ); + } + else if ( node->props == EADT_PROPS_NAN_NEG ) + { + _adt_fprintf( file, "-NaN" ); + } + else if ( node->props == EADT_PROPS_INFINITY ) + { + _adt_fprintf( file, "Infinity" ); + } + else if ( node->props == EADT_PROPS_INFINITY_NEG ) + { + _adt_fprintf( file, "-Infinity" ); + } + else if ( node->props == EADT_PROPS_TRUE ) + { + _adt_fprintf( file, "true" ); + } + else if ( node->props == EADT_PROPS_FALSE ) + { + _adt_fprintf( file, "false" ); + } + else if ( node->props == EADT_PROPS_NULL ) + { + _adt_fprintf( file, "null" ); +#ifndef GEN_PARSER_DISABLE_ANALYSIS + } + else if ( node->props == EADT_PROPS_IS_EXP ) + { + _adt_fprintf( file, "%lld.%0*d%llde%lld", ( long long )node->base, node->base2_offset, 0, ( long long )node->base2, ( long long )node->exp ); + } + else if ( node->props == EADT_PROPS_IS_PARSED_REAL ) + { + if ( ! node->lead_digit ) + _adt_fprintf( file, ".%0*d%lld", node->base2_offset, 0, ( long long )node->base2 ); + else + _adt_fprintf( file, "%lld.%0*d%lld", ( long long int )node->base2_offset, 0, ( int )node->base, ( long long )node->base2 ); +#endif + } + else + { + _adt_fprintf( file, "%f", node->real ); + } + } + break; + } + + return EADT_ERROR_NONE; +} + +ADT_Error adt_print_string( FileInfo* file, ADT_Node* node, char const* escaped_chars, char const* escape_symbol ) +{ + GEN_ASSERT_NOT_NULL( file ); + GEN_ASSERT_NOT_NULL( node ); + GEN_ASSERT_NOT_NULL( escaped_chars ); + if ( node->type != EADT_TYPE_STRING && node->type != EADT_TYPE_MULTISTRING ) + { + return EADT_ERROR_INVALID_TYPE; + } + + /* escape string */ + char const *p = node->string, *b = p; + + if ( ! p ) + return EADT_ERROR_NONE; + + do + { + p = c_str_skip_any( p, escaped_chars ); + _adt_fprintf( file, "%.*s", pointer_diff( b, p ), b ); + if ( *p && ! ! char_first_occurence( escaped_chars, *p ) ) + { + _adt_fprintf( file, "%s%c", escape_symbol, *p ); + p++; + } + b = p; + } while ( *p ); + + return EADT_ERROR_NONE; +} + +ADT_Error adt_c_str_to_number( ADT_Node* node ) +{ + GEN_ASSERT( node ); + + if ( node->type == EADT_TYPE_REAL || node->type == EADT_TYPE_INTEGER ) + return EADT_ERROR_ALREADY_CONVERTED; /* this is already converted/parsed */ + if ( node->type != EADT_TYPE_STRING && node->type != EADT_TYPE_MULTISTRING ) + { + return EADT_ERROR_INVALID_TYPE; + } + + adt_parse_number( node, ( char* )node->string ); + + return EADT_ERROR_NONE; +} + +ADT_Error adt_c_str_to_number_strict( ADT_Node* node ) +{ + GEN_ASSERT( node ); + + if ( node->type == EADT_TYPE_REAL || node->type == EADT_TYPE_INTEGER ) + return EADT_ERROR_ALREADY_CONVERTED; /* this is already converted/parsed */ + if ( node->type != EADT_TYPE_STRING && node->type != EADT_TYPE_MULTISTRING ) + { + return EADT_ERROR_INVALID_TYPE; + } + + adt_parse_number_strict( node, ( char* )node->string ); + + return EADT_ERROR_NONE; +} + +#undef _adt_fprintf + +#pragma endregion ADT + +#pragma region CSV + +#ifdef GEN_CSV_DEBUG +# define GEN_CSV_ASSERT( msg ) GEN_PANIC( msg ) +#else +# define GEN_CSV_ASSERT( msg ) +#endif + +u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header, char delim ) +{ + CSV_Error error = ECSV_Error__NONE; + GEN_ASSERT_NOT_NULL( root ); + GEN_ASSERT_NOT_NULL( text ); + zero_item( root ); + + adt_make_branch( root, allocator, NULL, has_header ? false : true ); + + char* currentChar = text; + char* beginChar; + char* endChar; + + ssize columnIndex = 0; + ssize totalColumnIndex = 0; + + do + { + char delimiter = 0; + currentChar = ccast( char*, c_str_trim( currentChar, false )); + + if ( *currentChar == 0 ) + break; + + ADT_Node rowItem = { 0 }; + rowItem.type = EADT_TYPE_STRING; + + #ifndef GEN_PARSER_DISABLE_ANALYSIS + rowItem.name_style = EADT_NAME_STYLE_NO_QUOTES; + #endif + + /* handle string literals */ + if ( *currentChar == '"' ) + { + currentChar += 1; + beginChar = currentChar; + endChar = currentChar; + rowItem.string = beginChar; + #ifndef GEN_PARSER_DISABLE_ANALYSIS + rowItem.name_style = EADT_NAME_STYLE_DOUBLE_QUOTE; + #endif + do + { + endChar = ccast( char*, c_str_skip( endChar, '"' )); + + if ( *endChar && *( endChar + 1 ) == '"' ) + { + endChar += 2; + } + else + break; + } + while ( *endChar ); + + if ( *endChar == 0 ) + { + GEN_CSV_ASSERT( "unmatched quoted string" ); + error = ECSV_Error__UNEXPECTED_END_OF_INPUT; + return error; + } + + *endChar = 0; + currentChar = ccast( char*, c_str_trim( endChar + 1, true )); + delimiter = * currentChar; + + /* unescape escaped quotes (so that unescaped text escapes :) */ + { + char* escapedChar = beginChar; + do + { + if ( *escapedChar == '"' && *( escapedChar + 1 ) == '"' ) + { + mem_move( escapedChar, escapedChar + 1, c_str_len( escapedChar ) ); + } + escapedChar++; + } + while ( *escapedChar ); + } + } + else if ( *currentChar == delim ) + { + delimiter = * currentChar; + rowItem.string = ""; + } + else if ( *currentChar ) + { + /* regular data */ + beginChar = currentChar; + endChar = currentChar; + rowItem.string = beginChar; + + do + { + endChar++; + } + while ( * endChar && * endChar != delim && * endChar != '\n' ); + + if ( * endChar ) + { + currentChar = ccast( char*, c_str_trim( endChar, true )); + + while ( char_is_space( *( endChar - 1 ) ) ) + { + endChar--; + } + + delimiter = * currentChar; + * endChar = 0; + } + else + { + delimiter = 0; + currentChar = endChar; + } + + /* check if number and process if so */ + b32 skip_number = false; + char* num_p = beginChar; + + // We only consider hexadecimal values if they start with 0x + if ( c_str_len(num_p) > 2 && num_p[0] == '0' && (num_p[1] == 'x' || num_p[1] == 'X') ) + { + num_p += 2; // skip '0x' prefix + do + { + if (!char_is_hex_digit(*num_p)) + { + skip_number = true; + break; + } + } while (*num_p++); + } + else + { + skip_number = true; + } + + if (!skip_number) + { + adt_c_str_to_number(&rowItem); + } + } + + if ( columnIndex >= scast(ssize, array_num(root->nodes)) ) + { + adt_append_arr( root, NULL ); + } + + array_append( root->nodes[ columnIndex ].nodes, rowItem ); + + if ( delimiter == delim ) + { + columnIndex++; + currentChar++; + } + else if ( delimiter == '\n' || delimiter == 0 ) + { + /* check if number of rows is not mismatched */ + if ( totalColumnIndex < columnIndex ) + totalColumnIndex = columnIndex; + + else if ( totalColumnIndex != columnIndex ) + { + GEN_CSV_ASSERT( "mismatched rows" ); + error = ECSV_Error__MISMATCHED_ROWS; + return error; + } + + columnIndex = 0; + + if ( delimiter != 0 ) + currentChar++; + } + } + while ( *currentChar ); + + if (array_num( root->nodes) == 0 ) + { + GEN_CSV_ASSERT( "unexpected end of input. stream is empty." ); + error = ECSV_Error__UNEXPECTED_END_OF_INPUT; + return error; + } + + /* consider first row as a header. */ + if ( has_header ) + { + for ( ssize i = 0; i < scast(ssize, array_num(root->nodes)); i++ ) + { + CSV_Object* col = root->nodes + i; + CSV_Object* hdr = col->nodes; + col->name = hdr->string; + array_remove_at(col->nodes, 0 ); + } + } + + return error; +} + +void csv_free( CSV_Object* obj ) +{ + adt_destroy_branch( obj ); +} + +void _csv_write_record( FileInfo* file, CSV_Object* node ) +{ + switch ( node->type ) + { + case EADT_TYPE_STRING : + { +#ifndef GEN_PARSER_DISABLE_ANALYSIS + switch ( node->name_style ) + { + case EADT_NAME_STYLE_DOUBLE_QUOTE : + { + c_str_fmt_file( file, "\"" ); + adt_print_string( file, node, "\"", "\"" ); + c_str_fmt_file( file, "\"" ); + } + break; + + case EADT_NAME_STYLE_NO_QUOTES : + { +#endif + c_str_fmt_file( file, "%s", node->string ); +#ifndef GEN_PARSER_DISABLE_ANALYSIS + } + break; + } +#endif + } + break; + + case EADT_TYPE_REAL : + case EADT_TYPE_INTEGER : + { + adt_print_number( file, node ); + } + break; + } +} + +void _csv_write_header( FileInfo* file, CSV_Object* header ) +{ + CSV_Object temp = *header; + temp.string = temp.name; + temp.type = EADT_TYPE_STRING; + _csv_write_record( file, &temp ); +} + +void csv_write_delimiter( FileInfo* file, CSV_Object* obj, char delimiter ) +{ + GEN_ASSERT_NOT_NULL( file ); + GEN_ASSERT_NOT_NULL( obj ); + GEN_ASSERT( obj->nodes ); + ssize cols = array_num(obj->nodes); + if ( cols == 0 ) + return; + + ssize rows = array_num(obj->nodes[ 0 ].nodes); + if ( rows == 0 ) + return; + + b32 has_headers = obj->nodes[ 0 ].name != NULL; + + if ( has_headers ) + { + for ( ssize i = 0; i < cols; i++ ) + { + _csv_write_header( file, &obj->nodes[ i ] ); + if ( i + 1 != cols ) + { + c_str_fmt_file( file, "%c", delimiter ); + } + } + c_str_fmt_file( file, "\n" ); + } + + for ( ssize r = 0; r < rows; r++ ) + { + for ( ssize i = 0; i < cols; i++ ) + { + _csv_write_record( file, &obj->nodes[ i ].nodes[ r ] ); + if ( i + 1 != cols ) + { + c_str_fmt_file( file, "%c", delimiter ); + } + } + c_str_fmt_file( file, "\n" ); + } +} + +StrBuilder csv_write_strbuilder_delimiter( AllocatorInfo a, CSV_Object* obj, char delimiter ) +{ + FileInfo tmp; + file_stream_new( &tmp, a ); + csv_write_delimiter( &tmp, obj, delimiter ); + + ssize fsize; + u8* buf = file_stream_buf( &tmp, &fsize ); + StrBuilder output = strbuilder_make_length( a, ( char* )buf, fsize ); + file_close( &tmp ); + return output; +} + +#undef _adt_fprintf + +#pragma endregion CSV + GEN_NS_END #ifdef __clang__ diff --git a/Project/Source/GasaEditor/GasaGen/gencpp/gen.dep.hpp b/Project/Source/GasaEditor/GasaGen/gencpp/gen.dep.hpp index b44ca0f..b82a2e7 100644 --- a/Project/Source/GasaEditor/GasaGen/gencpp/gen.dep.hpp +++ b/Project/Source/GasaEditor/GasaGen/gencpp/gen.dep.hpp @@ -883,7 +883,7 @@ template mem_ptr_const to_mem_ptr_const( Type ptr ) { return (mem // NOTE: Things that shouldn't happen with a message! #define GEN_PANIC( msg, ... ) GEN_ASSERT_MSG( 0, msg, ##__VA_ARGS__ ) -#if GEN_BULD_DEBUG +#if GEN_BUILD_DEBUG #define GEN_FATAL( ... ) \ do \ { \ @@ -1138,7 +1138,6 @@ FORCEINLINE void check(Arena& arena) { return arena_check(& arena); } #pragma pop_macro("check") #endif - inline AllocatorInfo arena_allocator_info( Arena* arena ) { GEN_ASSERT(arena != nullptr); @@ -1301,9 +1300,9 @@ void pool_clear(Pool* pool); void pool_free(Pool* pool); #if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP -AllocatorInfo allocator_info(Pool& pool) { return pool_allocator_info(& pool); } -void clear(Pool& pool) { return pool_clear(& pool); } -void free(Pool& pool) { return pool_free(& pool); } +FORCEINLINE AllocatorInfo allocator_info(Pool& pool) { return pool_allocator_info(& pool); } +FORCEINLINE void clear(Pool& pool) { return pool_clear(& pool); } +FORCEINLINE void free(Pool& pool) { return pool_free(& pool); } #endif struct Pool @@ -2042,6 +2041,7 @@ Array array_init_reserve(AllocatorInfo allocator, ssize capacity) return {rcast(Type*, header + 1)}; } +FORCEINLINE usize array_grow_formula(ssize value) { return 2 * value + 8; } @@ -2101,7 +2101,7 @@ bool array_append_at(Array* array, Type item, usize idx) ArrayHeader* header = array_get_header(* array); ssize slot = idx; - if (slot >= header->Num) + if (slot >= (ssize)(header->Num)) slot = header->Num - 1; if (slot < 0) @@ -2253,7 +2253,6 @@ bool array_reserve(Array* array, usize new_capacity) { GEN_ASSERT( array != nullptr); GEN_ASSERT(* array != nullptr); - GEN_ASSERT(num > 0) ArrayHeader* header = array_get_header(array); if (header->Capacity < new_capacity) @@ -2662,7 +2661,7 @@ HashTableFindResult hashtable__find(HashTable table, u64 key) } template FORCEINLINE -bool hashtable_full(HashTable table) { +b32 hashtable_full(HashTable table) { GEN_ASSERT_NOT_NULL(table.Hashes); GEN_ASSERT_NOT_NULL(table.Entries); usize critical_load = usize(HashTable_CriticalLoadScale * f32(array_num(table.Hashes))); @@ -3089,6 +3088,7 @@ bool strbuilder_append_string(StrBuilder* str, StrBuilder const other) { return strbuilder_append_c_str_len(str, (char const*)other, strbuilder_length(other)); } +inline bool strbuilder_append_fmt(StrBuilder* str, char const* fmt, ...) { GEN_ASSERT(str != nullptr); ssize res; @@ -3837,6 +3837,435 @@ u64 time_rel_ms( void ); #pragma endregion Timing +#pragma region ADT + +enum ADT_Type : u32 +{ + EADT_TYPE_UNINITIALISED, /* node was not initialised, this is a programming error! */ + EADT_TYPE_ARRAY, + EADT_TYPE_OBJECT, + EADT_TYPE_STRING, + EADT_TYPE_MULTISTRING, + EADT_TYPE_INTEGER, + EADT_TYPE_REAL, +}; + +enum ADT_Props : u32 +{ + EADT_PROPS_NONE, + EADT_PROPS_NAN, + EADT_PROPS_NAN_NEG, + EADT_PROPS_INFINITY, + EADT_PROPS_INFINITY_NEG, + EADT_PROPS_FALSE, + EADT_PROPS_TRUE, + EADT_PROPS_NULL, + EADT_PROPS_IS_EXP, + EADT_PROPS_IS_HEX, + + // Used internally so that people can fill in real numbers they plan to write. + EADT_PROPS_IS_PARSED_REAL, +}; + +enum ADT_NamingStyle : u32 +{ + EADT_NAME_STYLE_DOUBLE_QUOTE, + EADT_NAME_STYLE_SINGLE_QUOTE, + EADT_NAME_STYLE_NO_QUOTES, +}; + +enum ADT_AssignStyle : u32 +{ + EADT_ASSIGN_STYLE_COLON, + EADT_ASSIGN_STYLE_EQUALS, + EADT_ASSIGN_STYLE_LINE, +}; + +enum ADT_DelimStyle : u32 +{ + EADT_DELIM_STYLE_COMMA, + EADT_DELIM_STYLE_LINE, + EADT_DELIM_STYLE_NEWLINE, +}; + +enum ADT_Error : u32 +{ + EADT_ERROR_NONE, + EADT_ERROR_INTERNAL, + EADT_ERROR_ALREADY_CONVERTED, + EADT_ERROR_INVALID_TYPE, + EADT_ERROR_OUT_OF_MEMORY, +}; + +struct ADT_Node +{ + char const* name; + struct ADT_Node* parent; + + /* properties */ + ADT_Type type : 4; + u8 props : 4; +#ifndef GEN_PARSER_DISABLE_ANALYSIS + u8 cfg_mode : 1; + u8 name_style : 2; + u8 assign_style : 2; + u8 delim_style : 2; + u8 delim_line_width : 4; + u8 assign_line_width : 4; +#endif + + /* adt data */ + union + { + char const* string; + Array(ADT_Node) nodes; ///< zpl_array + + struct + { + union + { + f64 real; + s64 integer; + }; + +#ifndef GEN_PARSER_DISABLE_ANALYSIS + /* number analysis */ + s32 base; + s32 base2; + u8 base2_offset : 4; + s8 exp : 4; + u8 neg_zero : 1; + u8 lead_digit : 1; +#endif + }; + }; +}; + +/* ADT NODE LIMITS + * delimiter and assignment segment width is limited to 128 whitespace symbols each. + * real number limits decimal position to 128 places. + * real number exponent is limited to 64 digits. + */ + +/** + * @brief Initialise an ADT object or array + * + * @param node + * @param backing Memory allocator used for descendants + * @param name Node's name + * @param is_array + * @return error code + */ +u8 adt_make_branch( ADT_Node* node, AllocatorInfo backing, char const* name, b32 is_array ); + +/** + * @brief Destroy an ADT branch and its descendants + * + * @param node + * @return error code + */ +u8 adt_destroy_branch( ADT_Node* node ); + +/** + * @brief Initialise an ADT leaf + * + * @param node + * @param name Node's name + * @param type Node's type (use zpl_adt_make_branch for container nodes) + * @return error code + */ +u8 adt_make_leaf( ADT_Node* node, char const* name, ADT_Type type ); + + +/** + * @brief Fetch a node using provided URI string. + * + * This method uses a basic syntax to fetch a node from the ADT. The following features are available + * to retrieve the data: + * + * - "a/b/c" navigates through objects "a" and "b" to get to "c" + * - "arr/[foo=123]/bar" iterates over "arr" to find any object with param "foo" that matches the value "123", then gets its field called "bar" + * - "arr/3" retrieves the 4th element in "arr" + * - "arr/[apple]" retrieves the first element of value "apple" in "arr" + * + * @param node ADT node + * @param uri Locator string as described above + * @return zpl_adt_node* + * + * @see code/apps/examples/json_get.c + */ +ADT_Node* adt_query( ADT_Node* node, char const* uri ); + +/** + * @brief Find a field node within an object by the given name. + * + * @param node + * @param name + * @param deep_search Perform search recursively + * @return zpl_adt_node * node + */ +ADT_Node* adt_find( ADT_Node* node, char const* name, b32 deep_search ); + +/** + * @brief Allocate an unitialised node within a container at a specified index. + * + * @param parent + * @param index + * @return zpl_adt_node * node + */ +ADT_Node* adt_alloc_at( ADT_Node* parent, ssize index ); + +/** + * @brief Allocate an unitialised node within a container. + * + * @param parent + * @return zpl_adt_node * node + */ +ADT_Node* adt_alloc( ADT_Node* parent ); + +/** + * @brief Move an existing node to a new container at a specified index. + * + * @param node + * @param new_parent + * @param index + * @return zpl_adt_node * node + */ +ADT_Node* adt_move_node_at( ADT_Node* node, ADT_Node* new_parent, ssize index ); + +/** + * @brief Move an existing node to a new container. + * + * @param node + * @param new_parent + * @return zpl_adt_node * node + */ +ADT_Node* adt_move_node( ADT_Node* node, ADT_Node* new_parent ); + +/** + * @brief Swap two nodes. + * + * @param node + * @param other_node + * @return + */ +void adt_swap_nodes( ADT_Node* node, ADT_Node* other_node ); + +/** + * @brief Remove node from container. + * + * @param node + * @return + */ +void adt_remove_node( ADT_Node* node ); + +/** + * @brief Initialise a node as an object + * + * @param obj + * @param name + * @param backing + * @return + */ +b8 adt_set_obj( ADT_Node* obj, char const* name, AllocatorInfo backing ); + +/** + * @brief Initialise a node as an array + * + * @param obj + * @param name + * @param backing + * @return + */ +b8 adt_set_arr( ADT_Node* obj, char const* name, AllocatorInfo backing ); + +/** + * @brief Initialise a node as a string + * + * @param obj + * @param name + * @param value + * @return + */ +b8 adt_set_str( ADT_Node* obj, char const* name, char const* value ); + +/** + * @brief Initialise a node as a float + * + * @param obj + * @param name + * @param value + * @return + */ +b8 adt_set_flt( ADT_Node* obj, char const* name, f64 value ); + +/** + * @brief Initialise a node as a signed integer + * + * @param obj + * @param name + * @param value + * @return + */ +b8 adt_set_int( ADT_Node* obj, char const* name, s64 value ); + +/** + * @brief Append a new node to a container as an object + * + * @param parent + * @param name + * @return* + */ +ADT_Node* adt_append_obj( ADT_Node* parent, char const* name ); + +/** + * @brief Append a new node to a container as an array + * + * @param parent + * @param name + * @return* + */ +ADT_Node* adt_append_arr( ADT_Node* parent, char const* name ); + +/** + * @brief Append a new node to a container as a string + * + * @param parent + * @param name + * @param value + * @return* + */ +ADT_Node* adt_append_str( ADT_Node* parent, char const* name, char const* value ); + +/** + * @brief Append a new node to a container as a float + * + * @param parent + * @param name + * @param value + * @return* + */ +ADT_Node* adt_append_flt( ADT_Node* parent, char const* name, f64 value ); + +/** + * @brief Append a new node to a container as a signed integer + * + * @param parent + * @param name + * @param value + * @return* + */ +ADT_Node* adt_append_int( ADT_Node* parent, char const* name, s64 value ); + +/* parser helpers */ + +/** + * @brief Parses a text and stores the result into an unitialised node. + * + * @param node + * @param base + * @return* + */ +char* adt_parse_number( ADT_Node* node, char* base ); + +/** + * @brief Parses a text and stores the result into an unitialised node. + * This function expects the entire input to be a number. + * + * @param node + * @param base + * @return* + */ +char* adt_parse_number_strict( ADT_Node* node, char* base_str ); + +/** + * @brief Parses and converts an existing string node into a number. + * + * @param node + * @return + */ +ADT_Error adt_c_str_to_number( ADT_Node* node ); + +/** + * @brief Parses and converts an existing string node into a number. + * This function expects the entire input to be a number. + * + * @param node + * @return + */ +ADT_Error adt_c_str_to_number_strict( ADT_Node* node ); + +/** + * @brief Prints a number into a file stream. + * + * The provided file handle can also be a memory mapped stream. + * + * @see zpl_file_stream_new + * @param file + * @param node + * @return + */ +ADT_Error adt_print_number( FileInfo* file, ADT_Node* node ); + +/** + * @brief Prints a string into a file stream. + * + * The provided file handle can also be a memory mapped stream. + * + * @see zpl_file_stream_new + * @param file + * @param node + * @param escaped_chars + * @param escape_symbol + * @return + */ +ADT_Error adt_print_string( FileInfo* file, ADT_Node* node, char const* escaped_chars, char const* escape_symbol ); + +#pragma endregion ADT + +#pragma region CSV + +enum CSV_Error : u32 +{ + ECSV_Error__NONE, + ECSV_Error__INTERNAL, + ECSV_Error__UNEXPECTED_END_OF_INPUT, + ECSV_Error__MISMATCHED_ROWS, +}; + +typedef ADT_Node CSV_Object; + +u8 csv_parse( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header ); +u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header, char delim ); +void csv_free( CSV_Object* obj ); + +void csv_write( FileInfo* file, CSV_Object* obj ); +StrBuilder csv_write_string( AllocatorInfo a, CSV_Object* obj ); +void csv_write_delimiter( FileInfo* file, CSV_Object* obj, char delim ); +StrBuilder csv_write_strbuilder_delimiter( AllocatorInfo a, CSV_Object* obj, char delim ); + +/* inline */ + +inline +u8 csv_parse( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header ) +{ + return csv_parse_delimiter( root, text, allocator, has_header, ',' ); +} + +inline +void csv_write( FileInfo* file, CSV_Object* obj ) +{ + csv_write_delimiter( file, obj, ',' ); +} + +inline +StrBuilder csv_write_string( AllocatorInfo a, CSV_Object* obj ) +{ + return csv_write_strbuilder_delimiter( a, obj, ',' ); +} + +#pragma endregion CSV + GEN_NS_END #ifdef __clang__ diff --git a/Project/Source/GasaEditor/GasaGen/gencpp/gen.hpp b/Project/Source/GasaEditor/GasaGen/gencpp/gen.hpp index a39dc17..99b7b12 100644 --- a/Project/Source/GasaEditor/GasaGen/gencpp/gen.hpp +++ b/Project/Source/GasaEditor/GasaGen/gencpp/gen.hpp @@ -640,10 +640,11 @@ FORCEINLINE bool is_trailing( Specifier specifier ) return spec_is_trailing( specifier ); } -#define GEN_DEFINE_ATTRIBUTE_TOKENS \ - Entry( Tok_Attribute_API_Export, "GEN_API_Export_Code" ) Entry( Tok_Attribute_API_Import, "GEN_API_Import_Code" ) \ - Entry( Tok_Attribute_COREUOBJECT_API, "COREUOBJECT_API" ) Entry( Tok_Attribute_ENGINE_API, "ENGINE_API" ) \ - Entry( Tok_Attribute_GAMEPLAYABILITIES_API, "GAMEPLAYABILITIES_API" ) Entry( Tok_Attribute_UMG_API, "UMG_API" ) +#define GEN_DEFINE_ATTRIBUTE_TOKENS \ + Entry( Tok_Attribute_API_Export, "GEN_API_Export_Code" ) Entry( Tok_Attribute_API_Import, "GEN_API_Import_Code" ) \ + Entry( Tok_Attribute_COREUOBJECT_API, "COREUOBJECT_API" ) Entry( Tok_Attribute_ENGINE_API, "ENGINE_API" ) \ + Entry( Tok_Attribute_GAMEPLAYABILITIES_API, "GAMEPLAYABILITIES_API" ) Entry( Tok_Attribute_UMG_API, "UMG_API" ) \ + Entry( Tok_Attribute_GASA_API, "GASA_API" ) enum TokType : u32 { @@ -752,6 +753,7 @@ enum TokType : u32 Tok_Attribute_ENGINE_API, Tok_Attribute_GAMEPLAYABILITIES_API, Tok_Attribute_UMG_API, + Tok_Attribute_GASA_API, Tok_NumTokens }; @@ -863,6 +865,7 @@ inline Str toktype_to_str( TokType type ) { "ENGINE_API", sizeof( "ENGINE_API" ) - 1 }, { "GAMEPLAYABILITIES_API", sizeof( "GAMEPLAYABILITIES_API" ) - 1 }, { "UMG_API", sizeof( "UMG_API" ) - 1 }, + { "GASA_API", sizeof( "GASA_API" ) - 1 }, }; return lookup[type]; } @@ -1029,6 +1032,7 @@ TokType macrotype_to_toktype( MacroType type ) { return Tok_Invalid; } +inline Str macrotype_to_str( MacroType type ) { local_persist @@ -1093,6 +1097,11 @@ b32 macro_expects_body( Macro macro ) { return bitfield_is_set( b16, macro.Flags, MF_Expects_Body ); } +#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP +FORCEINLINE b32 is_functional( Macro macro ) { return bitfield_is_set( b16, macro.Flags, MF_Functional ); } +FORCEINLINE b32 expects_body ( Macro macro ) { return bitfield_is_set( b16, macro.Flags, MF_Expects_Body ); } +#endif + typedef HashTable(Macro) MacroTable; #pragma endregion Types @@ -3980,6 +3989,9 @@ GEN_API void init(Context* ctx); // However on Windows at least, it doesn't need to occur as the OS will clean up after the process. GEN_API void deinit(Context* ctx); +// Retrieves the active context (not usually needed, but here in case...) +GEN_API Context* get_context(); + // Clears the allocations, but doesn't free the memoery, then calls init() again. // Ease of use. GEN_API void reset(Context* ctx); @@ -4576,9 +4588,9 @@ FORCEINLINE void define_params_append (CodeDefineParams appendee FORCEINLINE CodeDefineParams define_params_get (CodeDefineParams self, s32 idx ) { return (CodeDefineParams) (Code) params_get( cast(CodeParams, self), idx); } FORCEINLINE bool define_params_has_entries(CodeDefineParams self) { return params_has_entries( cast(CodeParams, self)); } -CodeDefineParams begin_CodeDefineParams(CodeDefineParams params) { return (CodeDefineParams) (Code) begin_CodeParams( cast(CodeParams, (Code)params)); } -CodeDefineParams end_CodeDefineParams (CodeDefineParams params) { return (CodeDefineParams) (Code) end_CodeParams ( cast(CodeParams, (Code)params)); } -CodeDefineParams next_CodeDefineParams (CodeDefineParams params, CodeDefineParams entry_iter) { return (CodeDefineParams) (Code) next_CodeParams ( cast(CodeParams, (Code)params), cast(CodeParams, (Code)entry_iter)); } +FORCEINLINE CodeDefineParams begin_CodeDefineParams(CodeDefineParams params) { return (CodeDefineParams) (Code) begin_CodeParams( cast(CodeParams, (Code)params)); } +FORCEINLINE CodeDefineParams end_CodeDefineParams (CodeDefineParams params) { return (CodeDefineParams) (Code) end_CodeParams ( cast(CodeParams, (Code)params)); } +FORCEINLINE CodeDefineParams next_CodeDefineParams (CodeDefineParams params, CodeDefineParams entry_iter) { return (CodeDefineParams) (Code) next_CodeParams ( cast(CodeParams, (Code)params), cast(CodeParams, (Code)entry_iter)); } #if GEN_COMPILER_CPP FORCEINLINE diff --git a/Project/Source/GasaEditor/GasaGen/gencpp/gen.scanner.cpp b/Project/Source/GasaEditor/GasaGen/gencpp/gen.scanner.cpp index 177f619..fd915dc 100644 --- a/Project/Source/GasaEditor/GasaGen/gencpp/gen.scanner.cpp +++ b/Project/Source/GasaEditor/GasaGen/gencpp/gen.scanner.cpp @@ -26,1117 +26,150 @@ GEN_NS_BEGIN -#pragma region ADT +#pragma region Scanner -#define _adt_fprintf( s_, fmt_, ... ) \ - do \ - { \ - if ( c_str_fmt_file( s_, fmt_, ##__VA_ARGS__ ) < 0 ) \ - return EADT_ERROR_OUT_OF_MEMORY; \ - } while ( 0 ) - -u8 adt_make_branch( ADT_Node* node, AllocatorInfo backing, char const* name, b32 is_array ) +Code scan_file( char const* path ) { - ADT_Type type = EADT_TYPE_OBJECT; - if ( is_array ) - type = EADT_TYPE_ARRAY; + FileInfo file; - ADT_Node* parent = node->parent; - zero_item( node ); - - node->type = type; - node->name = name; - node->parent = parent; - node->nodes = array_init(ADT_Node, backing ); - - if ( ! node->nodes ) - return EADT_ERROR_OUT_OF_MEMORY; - - return 0; -} - -u8 adt_destroy_branch( ADT_Node* node ) -{ - GEN_ASSERT_NOT_NULL( node ); - if ( ( node->type == EADT_TYPE_OBJECT || node->type == EADT_TYPE_ARRAY ) && node->nodes ) + FileError error = file_open_mode( & file, EFileMode_READ, path ); + if ( error != EFileError_NONE ) { - for ( ssize i = 0; i < scast(ssize, array_num(node->nodes)); ++i ) + GEN_FATAL( "scan_file: Could not open: %s", path ); + } + + ssize fsize = file_size( & file ); + if ( fsize <= 0 ) + { + GEN_FATAL("scan_file: %s is empty", path ); + } + + StrBuilder str = strbuilder_make_reserve( get_context()->Allocator_Temp, fsize ); + file_read( & file, str, fsize ); + strbuilder_get_header(str)->Length = fsize; + + // Skip GEN_INTELLISENSE_DIRECTIVES preprocessor blocks + // Its designed so that the directive should be the first thing in the file. + // Anything that comes before it will also be omitted. + { + #define current (*scanner) + #define matched 0 + #define move_fwd() do { ++ scanner; -- left; } while (0) + const Str directive_start = txt( "ifdef" ); + const Str directive_end = txt( "endif" ); + const Str def_intellisense = txt("GEN_INTELLISENSE_DIRECTIVES" ); + + bool found_directive = false; + char const* scanner = (char const*)str; + s32 left = fsize; + while ( left ) { - adt_destroy_branch( node->nodes + i ); - } - - array_free(node->nodes); - } - return 0; -} - -u8 adt_make_leaf( ADT_Node* node, char const* name, ADT_Type type ) -{ - GEN_ASSERT( type != EADT_TYPE_OBJECT && type != EADT_TYPE_ARRAY ); - - ADT_Node* parent = node->parent; - zero_item( node ); - - node->type = type; - node->name = name; - node->parent = parent; - return 0; -} - -ADT_Node* adt_find( ADT_Node* node, char const* name, b32 deep_search ) -{ - if ( node->type != EADT_TYPE_OBJECT ) - { - return NULL; - } - - for ( ssize i = 0; i < scast(ssize, array_num(node->nodes)); i++ ) - { - if ( ! c_str_compare( node->nodes[ i ].name, name ) ) - { - return ( node->nodes + i ); - } - } - - if ( deep_search ) - { - for ( ssize i = 0; i < scast(ssize, array_num(node->nodes)); i++ ) - { - ADT_Node* res = adt_find( node->nodes + i, name, deep_search ); - - if ( res != NULL ) - return res; - } - } - - return NULL; -} - -internal ADT_Node* _adt_get_value( ADT_Node* node, char const* value ) -{ - switch ( node->type ) - { - case EADT_TYPE_MULTISTRING : - case EADT_TYPE_STRING : + // Processing directive. + if ( current == '#' ) { - if ( node->string && ! c_str_compare( node->string, value ) ) + move_fwd(); + while ( left && char_is_space( current ) ) + move_fwd(); + + if ( ! found_directive ) { - return node; - } - } - break; - case EADT_TYPE_INTEGER : - case EADT_TYPE_REAL : - { - char back[ 4096 ] = { 0 }; - FileInfo tmp; - - /* allocate a file descriptor for a memory-mapped number to string conversion, input source buffer is not cloned, however. */ - file_stream_open( &tmp, heap(), ( u8* )back, size_of( back ), EFileStream_WRITABLE ); - adt_print_number( &tmp, node ); - - ssize fsize = 0; - u8* buf = file_stream_buf( &tmp, &fsize ); - - if ( ! c_str_compare( ( char const* )buf, value ) ) - { - file_close( &tmp ); - return node; - } - - file_close( &tmp ); - } - break; - default : - break; /* node doesn't support value based lookup */ - } - - return NULL; -} - -internal ADT_Node* _adt_get_field( ADT_Node* node, char* name, char* value ) -{ - for ( ssize i = 0; i < scast(ssize, array_num(node->nodes)); i++ ) - { - if ( ! c_str_compare( node->nodes[ i ].name, name ) ) - { - ADT_Node* child = &node->nodes[ i ]; - if ( _adt_get_value( child, value ) ) - { - return node; /* this object does contain a field of a specified value! */ - } - } - } - - return NULL; -} - -ADT_Node* adt_query( ADT_Node* node, char const* uri ) -{ - GEN_ASSERT_NOT_NULL( uri ); - - if ( *uri == '/' ) - { - uri++; - } - - if ( *uri == 0 ) - { - return node; - } - - if ( ! node || ( node->type != EADT_TYPE_OBJECT && node->type != EADT_TYPE_ARRAY ) ) - { - return NULL; - } - -#if defined EADT_URI_DEBUG || 0 - c_str_fmt_out( "uri: %s\n", uri ); -#endif - - char * p = ( char* )uri, *b = p, *e = p; - ADT_Node* found_node = NULL; - - b = p; - p = e = ( char* )c_str_skip( p, '/' ); - char* buf = c_str_fmt_buf( "%.*s", ( int )( e - b ), b ); - - /* handle field value lookup */ - if ( *b == '[' ) - { - char *l_p = buf + 1, *l_b = l_p, *l_e = l_p, *l_b2 = l_p, *l_e2 = l_p; - l_e = ( char* )c_str_skip( l_p, '=' ); - l_e2 = ( char* )c_str_skip( l_p, ']' ); - - if ( ( ! *l_e && node->type != EADT_TYPE_ARRAY ) || ! *l_e2 ) - { - GEN_ASSERT_MSG( 0, "Invalid field value lookup" ); - return NULL; - } - - *l_e2 = 0; - - /* [field=value] */ - if ( *l_e ) - { - *l_e = 0; - l_b2 = l_e + 1; - - /* run a value comparison against our own fields */ - if ( node->type == EADT_TYPE_OBJECT ) - { - found_node = _adt_get_field( node, l_b, l_b2 ); - } - - /* run a value comparison against any child that is an object node */ - else if ( node->type == EADT_TYPE_ARRAY ) - { - for ( ssize i = 0; i < scast(ssize, array_num(node->nodes)); i++ ) - { - ADT_Node* child = &node->nodes[ i ]; - if ( child->type != EADT_TYPE_OBJECT ) + if ( left && c_str_compare_len( scanner, directive_start.Ptr, directive_start.Len ) == matched ) { - continue; + scanner += directive_start.Len; + left -= directive_start.Len; + + while ( left && char_is_space( current ) ) + move_fwd(); + + if ( left && c_str_compare_len( scanner, def_intellisense.Ptr, def_intellisense.Len ) == matched ) + { + scanner += def_intellisense.Len; + left -= def_intellisense.Len; + + found_directive = true; + } } - found_node = _adt_get_field( child, l_b, l_b2 ); + // Skip to end of line + while ( left && current != '\r' && current != '\n' ) + move_fwd(); + move_fwd(); - if ( found_node ) + if ( left && current == '\n' ) + move_fwd(); + + continue; + } + + if ( left && c_str_compare_len( 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) >= ( (char const*) str + fsize ) ) + { + mem_move( str, scanner, left ); + strbuilder_get_header(str)->Length = left; break; - } - } - } - /* [value] */ - else - { - for ( ssize i = 0; i < scast(ssize, array_num(node->nodes)); i++ ) - { - ADT_Node* child = &node->nodes[ i ]; - if ( _adt_get_value( child, l_b2 ) ) - { - found_node = child; - break; /* we found a matching value in array, ignore the rest of it */ - } - } - } + } - /* go deeper if uri continues */ - if ( *e ) - { - return adt_query( found_node, e + 1 ); - } - } - /* handle field name lookup */ - else if ( node->type == EADT_TYPE_OBJECT ) - { - found_node = adt_find( node, buf, false ); + mem_move( str, scanner, left ); + strbuilder_get_header(str)->Length = left; - /* go deeper if uri continues */ - if ( *e ) - { - return adt_query( found_node, e + 1 ); - } - } - /* handle array index lookup */ - else - { - ssize idx = ( ssize )c_str_to_i64( buf, NULL, 10 ); - if ( idx >= 0 && idx < scast(ssize, array_num(node->nodes)) ) - { - found_node = &node->nodes[ idx ]; - - /* go deeper if uri continues */ - if ( *e ) - { - return adt_query( found_node, e + 1 ); - } - } - } - - return found_node; -} - -ADT_Node* adt_alloc_at( ADT_Node* parent, ssize index ) -{ - if ( ! parent || ( parent->type != EADT_TYPE_OBJECT && parent->type != EADT_TYPE_ARRAY ) ) - { - return NULL; - } - - if ( ! parent->nodes ) - return NULL; - - if ( index < 0 || index > scast(ssize, array_num(parent->nodes)) ) - return NULL; - - ADT_Node o = { 0 }; - o.parent = parent; - if ( ! array_append_at( parent->nodes, o, index ) ) - return NULL; - - ADT_Node* node = & parent->nodes[index]; - return node; -} - -ADT_Node* adt_alloc( ADT_Node* parent ) -{ - if ( ! parent || ( parent->type != EADT_TYPE_OBJECT && parent->type != EADT_TYPE_ARRAY ) ) - { - return NULL; - } - - if ( ! parent->nodes ) - return NULL; - - return adt_alloc_at( parent, array_num(parent->nodes) ); -} - -b8 adt_set_obj( ADT_Node* obj, char const* name, AllocatorInfo backing ) -{ - return adt_make_branch( obj, backing, name, 0 ); -} - -b8 adt_set_arr( ADT_Node* obj, char const* name, AllocatorInfo backing ) -{ - return adt_make_branch( obj, backing, name, 1 ); -} - -b8 adt_set_str( ADT_Node* obj, char const* name, char const* value ) -{ - adt_make_leaf( obj, name, EADT_TYPE_STRING ); - obj->string = value; - return true; -} - -b8 adt_set_flt( ADT_Node* obj, char const* name, f64 value ) -{ - adt_make_leaf( obj, name, EADT_TYPE_REAL ); - obj->real = value; - return true; -} - -b8 adt_set_int( ADT_Node* obj, char const* name, s64 value ) -{ - adt_make_leaf( obj, name, EADT_TYPE_INTEGER ); - obj->integer = value; - return true; -} - -ADT_Node* adt_move_node_at( ADT_Node* node, ADT_Node* new_parent, ssize index ) -{ - GEN_ASSERT_NOT_NULL( node ); - GEN_ASSERT_NOT_NULL( new_parent ); - ADT_Node* old_parent = node->parent; - ADT_Node* new_node = adt_alloc_at( new_parent, index ); - *new_node = *node; - new_node->parent = new_parent; - if ( old_parent ) - { - adt_remove_node( node ); - } - return new_node; -} - -ADT_Node* adt_move_node( ADT_Node* node, ADT_Node* new_parent ) -{ - GEN_ASSERT_NOT_NULL( node ); - GEN_ASSERT_NOT_NULL( new_parent ); - GEN_ASSERT( new_parent->type == EADT_TYPE_ARRAY || new_parent->type == EADT_TYPE_OBJECT ); - return adt_move_node_at( node, new_parent, array_num(new_parent->nodes) ); -} - -void adt_swap_nodes( ADT_Node* node, ADT_Node* other_node ) -{ - GEN_ASSERT_NOT_NULL( node ); - GEN_ASSERT_NOT_NULL( other_node ); - ADT_Node* parent = node->parent; - ADT_Node* other_parent = other_node->parent; - ssize index = ( pointer_diff( parent->nodes, node ) / size_of( ADT_Node ) ); - ssize index2 = ( pointer_diff( other_parent->nodes, other_node ) / size_of( ADT_Node ) ); - ADT_Node temp = parent->nodes[ index ]; - temp.parent = other_parent; - other_parent->nodes[ index2 ].parent = parent; - parent->nodes[ index ] = other_parent->nodes[ index2 ]; - other_parent->nodes[ index2 ] = temp; -} - -void adt_remove_node( ADT_Node* node ) -{ - GEN_ASSERT_NOT_NULL( node ); - GEN_ASSERT_NOT_NULL( node->parent ); - ADT_Node* parent = node->parent; - ssize index = ( pointer_diff( parent->nodes, node ) / size_of( ADT_Node ) ); - array_remove_at( parent->nodes, index ); -} - -ADT_Node* adt_append_obj( ADT_Node* parent, char const* name ) -{ - ADT_Node* o = adt_alloc( parent ); - if ( ! o ) - return NULL; - if ( adt_set_obj( o, name, array_get_header(parent->nodes)->Allocator ) ) - { - adt_remove_node( o ); - return NULL; - } - return o; -} - -ADT_Node* adt_append_arr( ADT_Node* parent, char const* name ) -{ - ADT_Node* o = adt_alloc( parent ); - if ( ! o ) - return NULL; - - ArrayHeader* node_header = array_get_header(parent->nodes); - if ( adt_set_arr( o, name, node_header->Allocator ) ) - { - adt_remove_node( o ); - return NULL; - } - return o; -} - -ADT_Node* adt_append_str( ADT_Node* parent, char const* name, char const* value ) -{ - ADT_Node* o = adt_alloc( parent ); - if ( ! o ) - return NULL; - adt_set_str( o, name, value ); - return o; -} - -ADT_Node* adt_append_flt( ADT_Node* parent, char const* name, f64 value ) -{ - ADT_Node* o = adt_alloc( parent ); - if ( ! o ) - return NULL; - adt_set_flt( o, name, value ); - return o; -} - -ADT_Node* adt_append_int( ADT_Node* parent, char const* name, s64 value ) -{ - ADT_Node* o = adt_alloc( parent ); - if ( ! o ) - return NULL; - adt_set_int( o, name, value ); - return o; -} - -/* parser helpers */ -char* adt_parse_number_strict( ADT_Node* node, char* base_str ) -{ - GEN_ASSERT_NOT_NULL( node ); - GEN_ASSERT_NOT_NULL( base_str ); - char *p = base_str, *e = p; - - while ( *e ) - ++e; - - while ( *p && ( char_first_occurence( "eE.+-", *p ) || char_is_hex_digit( *p ) ) ) - { - ++p; - } - - if ( p >= e ) - { - return adt_parse_number( node, base_str ); - } - - return base_str; -} - -char* adt_parse_number( ADT_Node* node, char* base_str ) -{ - GEN_ASSERT_NOT_NULL( node ); - GEN_ASSERT_NOT_NULL( base_str ); - char *p = base_str, *e = p; - - s32 base = 0; - s32 base2 = 0; - u8 base2_offset = 0; - s8 exp = 0, orig_exp = 0; - u8 neg_zero = 0; - u8 lead_digit = 0; - ADT_Type node_type = EADT_TYPE_UNINITIALISED; - u8 node_props = 0; - - /* skip false positives and special cases */ - if ( ! ! char_first_occurence( "eE", *p ) || ( ! ! char_first_occurence( ".+-", *p ) && ! char_is_hex_digit( *( p + 1 ) ) && *( p + 1 ) != '.' ) ) - { - return ++base_str; - } - - node_type = EADT_TYPE_INTEGER; - neg_zero = false; - - ssize ib = 0; - char buf[ 48 ] = { 0 }; - - if ( *e == '+' ) - ++e; - else if ( *e == '-' ) - { - buf[ ib++ ] = *e++; - } - - if ( *e == '.' ) - { - node_type = EADT_TYPE_REAL; - node_props = EADT_PROPS_IS_PARSED_REAL; - lead_digit = false; - buf[ ib++ ] = '0'; - do - { - buf[ ib++ ] = *e; - } while ( char_is_digit( *++e ) ); - } - else - { - if ( ! c_str_compare_len( e, "0x", 2 ) || ! c_str_compare_len( e, "0X", 2 ) ) - { - node_props = EADT_PROPS_IS_HEX; - } - - /* bail if ZPL_ADT_PROPS_IS_HEX is unset but we get 'x' on input */ - if ( char_to_lower( *e ) == 'x' && ( node_props != EADT_PROPS_IS_HEX ) ) - { - return ++base_str; - } - - while ( char_is_hex_digit( *e ) || char_to_lower( *e ) == 'x' ) - { - buf[ ib++ ] = *e++; - } - - if ( *e == '.' ) - { - node_type = EADT_TYPE_REAL; - lead_digit = true; - u32 step = 0; - - do - { - buf[ ib++ ] = *e; - ++step; - } while ( char_is_digit( *++e ) ); - - if ( step < 2 ) - { - buf[ ib++ ] = '0'; - } - } - } - - /* check if we have a dot here, this is a false positive (IP address, ...) */ - if ( *e == '.' ) - { - return ++base_str; - } - - f32 eb = 10; - char expbuf[ 6 ] = { 0 }; - ssize expi = 0; - - if ( *e && ! ! char_first_occurence( "eE", *e ) ) - { - ++e; - if ( *e == '+' || *e == '-' || char_is_digit( *e ) ) - { - if ( *e == '-' ) - { - eb = 0.1f; - } - if ( ! char_is_digit( *e ) ) - { - ++e; - } - while ( char_is_digit( *e ) ) - { - expbuf[ expi++ ] = *e++; - } - } - - orig_exp = exp = ( u8 )c_str_to_i64( expbuf, NULL, 10 ); - } - - if ( node_type == EADT_TYPE_INTEGER ) - { - node->integer = c_str_to_i64( buf, 0, 0 ); -#ifndef GEN_PARSER_DISABLE_ANALYSIS - /* special case: negative zero */ - if ( node->integer == 0 && buf[ 0 ] == '-' ) - { - neg_zero = true; - } -#endif - while ( orig_exp-- > 0 ) - { - node->integer *= ( s64 )eb; - } - } - else - { - node->real = c_str_to_f64( buf, 0 ); - -#ifndef GEN_PARSER_DISABLE_ANALYSIS - char *q = buf, *base_string = q, *base_string2 = q; - base_string = ccast( char*, c_str_skip( base_string, '.' )); - *base_string = '\0'; - base_string2 = base_string + 1; - char* base_strbuilder_off = base_string2; - while ( *base_strbuilder_off++ == '0' ) - base2_offset++; - - base = ( s32 )c_str_to_i64( q, 0, 0 ); - base2 = ( s32 )c_str_to_i64( base_string2, 0, 0 ); - if ( exp ) - { - exp = exp * ( ! ( eb == 10.0f ) ? -1 : 1 ); - node_props = EADT_PROPS_IS_EXP; - } - - /* special case: negative zero */ - if ( base == 0 && buf[ 0 ] == '-' ) - { - neg_zero = true; - } -#endif - while ( orig_exp-- > 0 ) - { - node->real *= eb; - } - } - - node->type = node_type; - node->props = node_props; - -#ifndef GEN_PARSER_DISABLE_ANALYSIS - node->base = base; - node->base2 = base2; - node->base2_offset = base2_offset; - node->exp = exp; - node->neg_zero = neg_zero; - node->lead_digit = lead_digit; -#else - unused( base ); - unused( base2 ); - unused( base2_offset ); - unused( exp ); - unused( neg_zero ); - unused( lead_digit ); -#endif - return e; -} - -ADT_Error adt_print_number( FileInfo* file, ADT_Node* node ) -{ - GEN_ASSERT_NOT_NULL( file ); - GEN_ASSERT_NOT_NULL( node ); - if ( node->type != EADT_TYPE_INTEGER && node->type != EADT_TYPE_REAL ) - { - return EADT_ERROR_INVALID_TYPE; - } - -#ifndef GEN_PARSER_DISABLE_ANALYSIS - if ( node->neg_zero ) - { - _adt_fprintf( file, "-" ); - } -#endif - - switch ( node->type ) - { - case EADT_TYPE_INTEGER : - { - if ( node->props == EADT_PROPS_IS_HEX ) - { - _adt_fprintf( file, "0x%llx", ( long long )node->integer ); - } - else - { - _adt_fprintf( file, "%lld", ( long long )node->integer ); - } - } - break; - - case EADT_TYPE_REAL : - { - if ( node->props == EADT_PROPS_NAN ) - { - _adt_fprintf( file, "NaN" ); - } - else if ( node->props == EADT_PROPS_NAN_NEG ) - { - _adt_fprintf( file, "-NaN" ); - } - else if ( node->props == EADT_PROPS_INFINITY ) - { - _adt_fprintf( file, "Infinity" ); - } - else if ( node->props == EADT_PROPS_INFINITY_NEG ) - { - _adt_fprintf( file, "-Infinity" ); - } - else if ( node->props == EADT_PROPS_TRUE ) - { - _adt_fprintf( file, "true" ); - } - else if ( node->props == EADT_PROPS_FALSE ) - { - _adt_fprintf( file, "false" ); - } - else if ( node->props == EADT_PROPS_NULL ) - { - _adt_fprintf( file, "null" ); -#ifndef GEN_PARSER_DISABLE_ANALYSIS - } - else if ( node->props == EADT_PROPS_IS_EXP ) - { - _adt_fprintf( file, "%lld.%0*d%llde%lld", ( long long )node->base, node->base2_offset, 0, ( long long )node->base2, ( long long )node->exp ); - } - else if ( node->props == EADT_PROPS_IS_PARSED_REAL ) - { - if ( ! node->lead_digit ) - _adt_fprintf( file, ".%0*d%lld", node->base2_offset, 0, ( long long )node->base2 ); - else - _adt_fprintf( file, "%lld.%0*d%lld", ( long long int )node->base2_offset, 0, ( int )node->base, ( long long )node->base2 ); -#endif - } - else - { - _adt_fprintf( file, "%f", node->real ); - } - } - break; - } - - return EADT_ERROR_NONE; -} - -ADT_Error adt_print_string( FileInfo* file, ADT_Node* node, char const* escaped_chars, char const* escape_symbol ) -{ - GEN_ASSERT_NOT_NULL( file ); - GEN_ASSERT_NOT_NULL( node ); - GEN_ASSERT_NOT_NULL( escaped_chars ); - if ( node->type != EADT_TYPE_STRING && node->type != EADT_TYPE_MULTISTRING ) - { - return EADT_ERROR_INVALID_TYPE; - } - - /* escape string */ - char const *p = node->string, *b = p; - - if ( ! p ) - return EADT_ERROR_NONE; - - do - { - p = c_str_skip_any( p, escaped_chars ); - _adt_fprintf( file, "%.*s", pointer_diff( b, p ), b ); - if ( *p && ! ! char_first_occurence( escaped_chars, *p ) ) - { - _adt_fprintf( file, "%s%c", escape_symbol, *p ); - p++; - } - b = p; - } while ( *p ); - - return EADT_ERROR_NONE; -} - -ADT_Error adt_c_str_to_number( ADT_Node* node ) -{ - GEN_ASSERT( node ); - - if ( node->type == EADT_TYPE_REAL || node->type == EADT_TYPE_INTEGER ) - return EADT_ERROR_ALREADY_CONVERTED; /* this is already converted/parsed */ - if ( node->type != EADT_TYPE_STRING && node->type != EADT_TYPE_MULTISTRING ) - { - return EADT_ERROR_INVALID_TYPE; - } - - adt_parse_number( node, ( char* )node->string ); - - return EADT_ERROR_NONE; -} - -ADT_Error adt_c_str_to_number_strict( ADT_Node* node ) -{ - GEN_ASSERT( node ); - - if ( node->type == EADT_TYPE_REAL || node->type == EADT_TYPE_INTEGER ) - return EADT_ERROR_ALREADY_CONVERTED; /* this is already converted/parsed */ - if ( node->type != EADT_TYPE_STRING && node->type != EADT_TYPE_MULTISTRING ) - { - return EADT_ERROR_INVALID_TYPE; - } - - adt_parse_number_strict( node, ( char* )node->string ); - - return EADT_ERROR_NONE; -} - -#undef _adt_fprintf - -#pragma endregion ADT - -#pragma region CSV - -#ifdef GEN_CSV_DEBUG -# define GEN_CSV_ASSERT( msg ) GEN_PANIC( msg ) -#else -# define GEN_CSV_ASSERT( msg ) -#endif - -u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header, char delim ) -{ - CSV_Error error = ECSV_Error__NONE; - GEN_ASSERT_NOT_NULL( root ); - GEN_ASSERT_NOT_NULL( text ); - zero_item( root ); - - adt_make_branch( root, allocator, NULL, has_header ? false : true ); - - char* currentChar = text; - char* beginChar; - char* endChar; - - ssize columnIndex = 0; - ssize totalColumnIndex = 0; - - do - { - char delimiter = 0; - currentChar = ccast( char*, c_str_trim( currentChar, false )); - - if ( *currentChar == 0 ) - break; - - ADT_Node rowItem = { 0 }; - rowItem.type = EADT_TYPE_STRING; - - #ifndef GEN_PARSER_DISABLE_ANALYSIS - rowItem.name_style = EADT_NAME_STYLE_NO_QUOTES; - #endif - - /* handle string literals */ - if ( *currentChar == '"' ) - { - currentChar += 1; - beginChar = currentChar; - endChar = currentChar; - rowItem.string = beginChar; - #ifndef GEN_PARSER_DISABLE_ANALYSIS - rowItem.name_style = EADT_NAME_STYLE_DOUBLE_QUOTE; - #endif - do - { - endChar = ccast( char*, c_str_skip( endChar, '"' )); - - if ( *endChar && *( endChar + 1 ) == '"' ) - { - endChar += 2; - } - else break; - } - while ( *endChar ); - - if ( *endChar == 0 ) - { - GEN_CSV_ASSERT( "unmatched quoted string" ); - error = ECSV_Error__UNEXPECTED_END_OF_INPUT; - return error; - } - - *endChar = 0; - currentChar = ccast( char*, c_str_trim( endChar + 1, true )); - delimiter = * currentChar; - - /* unescape escaped quotes (so that unescaped text escapes :) */ - { - char* escapedChar = beginChar; - do - { - if ( *escapedChar == '"' && *( escapedChar + 1 ) == '"' ) - { - mem_move( escapedChar, escapedChar + 1, c_str_len( escapedChar ) ); - } - escapedChar++; } - while ( *escapedChar ); } + + move_fwd(); } - else if ( *currentChar == delim ) - { - delimiter = * currentChar; - rowItem.string = ""; - } - else if ( *currentChar ) - { - /* regular data */ - beginChar = currentChar; - endChar = currentChar; - rowItem.string = beginChar; - - do - { - endChar++; - } - while ( * endChar && * endChar != delim && * endChar != '\n' ); - - if ( * endChar ) - { - currentChar = ccast( char*, c_str_trim( endChar, true )); - - while ( char_is_space( *( endChar - 1 ) ) ) - { - endChar--; - } - - delimiter = * currentChar; - * endChar = 0; - } - else - { - delimiter = 0; - currentChar = endChar; - } - - /* check if number and process if so */ - b32 skip_number = false; - char* num_p = beginChar; - - // We only consider hexadecimal values if they start with 0x - if ( c_str_len(num_p) > 2 && num_p[0] == '0' && (num_p[1] == 'x' || num_p[1] == 'X') ) - { - num_p += 2; // skip '0x' prefix - do - { - if (!char_is_hex_digit(*num_p)) - { - skip_number = true; - break; - } - } while (*num_p++); - } - else - { - skip_number = true; - } - - if (!skip_number) - { - adt_c_str_to_number(&rowItem); - } - } - - if ( columnIndex >= scast(ssize, array_num(root->nodes)) ) - { - adt_append_arr( root, NULL ); - } - - array_append( root->nodes[ columnIndex ].nodes, rowItem ); - - if ( delimiter == delim ) - { - columnIndex++; - currentChar++; - } - else if ( delimiter == '\n' || delimiter == 0 ) - { - /* check if number of rows is not mismatched */ - if ( totalColumnIndex < columnIndex ) - totalColumnIndex = columnIndex; - - else if ( totalColumnIndex != columnIndex ) - { - GEN_CSV_ASSERT( "mismatched rows" ); - error = ECSV_Error__MISMATCHED_ROWS; - return error; - } - - columnIndex = 0; - - if ( delimiter != 0 ) - currentChar++; - } - } - while ( *currentChar ); - - if (array_num( root->nodes) == 0 ) - { - GEN_CSV_ASSERT( "unexpected end of input. stream is empty." ); - error = ECSV_Error__UNEXPECTED_END_OF_INPUT; - return error; + #undef move_fwd + #undef matched + #undef current } - /* consider first row as a header. */ - if ( has_header ) - { - for ( ssize i = 0; i < scast(ssize, array_num(root->nodes)); i++ ) - { - CSV_Object* col = root->nodes + i; - CSV_Object* hdr = col->nodes; - col->name = hdr->string; - array_remove_at(col->nodes, 0 ); - } - } - - return error; + file_close( & file ); + return untyped_str( strbuilder_to_str(str) ); } -void csv_free( CSV_Object* obj ) -{ - adt_destroy_branch( obj ); +CodeBody parse_file( const char* path ) { + FileContents file = file_read_contents( get_context()->Allocator_Temp, true, path ); + Str content = { (char const*)file.data, file.size }; + CodeBody code = parse_global_body( content ); + log_fmt("\nParsed: %s\n", path); + return code; } -void _csv_write_record( FileInfo* file, CSV_Object* node ) -{ - switch ( node->type ) - { - case EADT_TYPE_STRING : - { -#ifndef GEN_PARSER_DISABLE_ANALYSIS - switch ( node->name_style ) - { - case EADT_NAME_STYLE_DOUBLE_QUOTE : - { - c_str_fmt_file( file, "\"" ); - adt_print_string( file, node, "\"", "\"" ); - c_str_fmt_file( file, "\"" ); - } - break; +CSV_Column parse_csv_one_column(AllocatorInfo allocator, char const* path) { + FileContents content = file_read_contents( allocator, file_zero_terminate, path ); + Arena csv_arena = arena_init_from_memory(content.data, content.size); - case EADT_NAME_STYLE_NO_QUOTES : - { -#endif - c_str_fmt_file( file, "%s", node->string ); -#ifndef GEN_PARSER_DISABLE_ANALYSIS - } - break; - } -#endif - } - break; - - case EADT_TYPE_REAL : - case EADT_TYPE_INTEGER : - { - adt_print_number( file, node ); - } - break; - } + CSV_Column result; + csv_parse( & result.ADT, rcast(char*, content.data), allocator, false ); + result.Content = result.ADT.nodes[0].nodes; + return result; } -void _csv_write_header( FileInfo* file, CSV_Object* header ) -{ - CSV_Object temp = *header; - temp.string = temp.name; - temp.type = EADT_TYPE_STRING; - _csv_write_record( file, &temp ); +CSV_Columns2 parse_csv_two_columns(AllocatorInfo allocator, char const* path) { + FileContents content = file_read_contents( allocator, file_zero_terminate, path ); + Arena csv_arena = arena_init_from_memory(content.data, content.size); + + CSV_Columns2 result; + csv_parse( & result.ADT, rcast(char*, content.data), allocator, false ); + result.Col_1 = result.ADT.nodes[0].nodes; + result.Col_2 = result.ADT.nodes[1].nodes; + return result; } -void csv_write_delimiter( FileInfo* file, CSV_Object* obj, char delimiter ) -{ - GEN_ASSERT_NOT_NULL( file ); - GEN_ASSERT_NOT_NULL( obj ); - GEN_ASSERT( obj->nodes ); - ssize cols = array_num(obj->nodes); - if ( cols == 0 ) - return; - - ssize rows = array_num(obj->nodes[ 0 ].nodes); - if ( rows == 0 ) - return; - - b32 has_headers = obj->nodes[ 0 ].name != NULL; - - if ( has_headers ) - { - for ( ssize i = 0; i < cols; i++ ) - { - _csv_write_header( file, &obj->nodes[ i ] ); - if ( i + 1 != cols ) - { - c_str_fmt_file( file, "%c", delimiter ); - } - } - c_str_fmt_file( file, "\n" ); - } - - for ( ssize r = 0; r < rows; r++ ) - { - for ( ssize i = 0; i < cols; i++ ) - { - _csv_write_record( file, &obj->nodes[ i ].nodes[ r ] ); - if ( i + 1 != cols ) - { - c_str_fmt_file( file, "%c", delimiter ); - } - } - c_str_fmt_file( file, "\n" ); - } -} - -StrBuilder csv_write_strbuilder_delimiter( AllocatorInfo a, CSV_Object* obj, char delimiter ) -{ - FileInfo tmp; - file_stream_new( &tmp, a ); - csv_write_delimiter( &tmp, obj, delimiter ); - - ssize fsize; - u8* buf = file_stream_buf( &tmp, &fsize ); - StrBuilder output = strbuilder_make_length( a, ( char* )buf, fsize ); - file_close( &tmp ); - return output; -} - -#undef _adt_fprintf - -#pragma endregion CSV +#pragma endregion Scanner GEN_NS_END diff --git a/Project/Source/GasaEditor/GasaGen/gencpp/gen.scanner.hpp b/Project/Source/GasaEditor/GasaGen/gencpp/gen.scanner.hpp index 965bf61..487a67c 100644 --- a/Project/Source/GasaEditor/GasaGen/gencpp/gen.scanner.hpp +++ b/Project/Source/GasaEditor/GasaGen/gencpp/gen.scanner.hpp @@ -28,435 +28,6 @@ GEN_NS_BEGIN -#pragma region ADT - -enum ADT_Type : u32 -{ - EADT_TYPE_UNINITIALISED, /* node was not initialised, this is a programming error! */ - EADT_TYPE_ARRAY, - EADT_TYPE_OBJECT, - EADT_TYPE_STRING, - EADT_TYPE_MULTISTRING, - EADT_TYPE_INTEGER, - EADT_TYPE_REAL, -}; - -enum ADT_Props : u32 -{ - EADT_PROPS_NONE, - EADT_PROPS_NAN, - EADT_PROPS_NAN_NEG, - EADT_PROPS_INFINITY, - EADT_PROPS_INFINITY_NEG, - EADT_PROPS_FALSE, - EADT_PROPS_TRUE, - EADT_PROPS_NULL, - EADT_PROPS_IS_EXP, - EADT_PROPS_IS_HEX, - - // Used internally so that people can fill in real numbers they plan to write. - EADT_PROPS_IS_PARSED_REAL, -}; - -enum ADT_NamingStyle : u32 -{ - EADT_NAME_STYLE_DOUBLE_QUOTE, - EADT_NAME_STYLE_SINGLE_QUOTE, - EADT_NAME_STYLE_NO_QUOTES, -}; - -enum ADT_AssignStyle : u32 -{ - EADT_ASSIGN_STYLE_COLON, - EADT_ASSIGN_STYLE_EQUALS, - EADT_ASSIGN_STYLE_LINE, -}; - -enum ADT_DelimStyle : u32 -{ - EADT_DELIM_STYLE_COMMA, - EADT_DELIM_STYLE_LINE, - EADT_DELIM_STYLE_NEWLINE, -}; - -enum ADT_Error : u32 -{ - EADT_ERROR_NONE, - EADT_ERROR_INTERNAL, - EADT_ERROR_ALREADY_CONVERTED, - EADT_ERROR_INVALID_TYPE, - EADT_ERROR_OUT_OF_MEMORY, -}; - -struct ADT_Node -{ - char const* name; - struct ADT_Node* parent; - - /* properties */ - ADT_Type type : 4; - u8 props : 4; -#ifndef GEN_PARSER_DISABLE_ANALYSIS - u8 cfg_mode : 1; - u8 name_style : 2; - u8 assign_style : 2; - u8 delim_style : 2; - u8 delim_line_width : 4; - u8 assign_line_width : 4; -#endif - - /* adt data */ - union - { - char const* string; - Array(ADT_Node) nodes; ///< zpl_array - - struct - { - union - { - f64 real; - s64 integer; - }; - -#ifndef GEN_PARSER_DISABLE_ANALYSIS - /* number analysis */ - s32 base; - s32 base2; - u8 base2_offset : 4; - s8 exp : 4; - u8 neg_zero : 1; - u8 lead_digit : 1; -#endif - }; - }; -}; - -/* ADT NODE LIMITS - * delimiter and assignment segment width is limited to 128 whitespace symbols each. - * real number limits decimal position to 128 places. - * real number exponent is limited to 64 digits. - */ - -/** - * @brief Initialise an ADT object or array - * - * @param node - * @param backing Memory allocator used for descendants - * @param name Node's name - * @param is_array - * @return error code - */ -u8 adt_make_branch( ADT_Node* node, AllocatorInfo backing, char const* name, b32 is_array ); - -/** - * @brief Destroy an ADT branch and its descendants - * - * @param node - * @return error code - */ -u8 adt_destroy_branch( ADT_Node* node ); - -/** - * @brief Initialise an ADT leaf - * - * @param node - * @param name Node's name - * @param type Node's type (use zpl_adt_make_branch for container nodes) - * @return error code - */ -u8 adt_make_leaf( ADT_Node* node, char const* name, ADT_Type type ); - - -/** - * @brief Fetch a node using provided URI string. - * - * This method uses a basic syntax to fetch a node from the ADT. The following features are available - * to retrieve the data: - * - * - "a/b/c" navigates through objects "a" and "b" to get to "c" - * - "arr/[foo=123]/bar" iterates over "arr" to find any object with param "foo" that matches the value "123", then gets its field called "bar" - * - "arr/3" retrieves the 4th element in "arr" - * - "arr/[apple]" retrieves the first element of value "apple" in "arr" - * - * @param node ADT node - * @param uri Locator string as described above - * @return zpl_adt_node* - * - * @see code/apps/examples/json_get.c - */ -ADT_Node* adt_query( ADT_Node* node, char const* uri ); - -/** - * @brief Find a field node within an object by the given name. - * - * @param node - * @param name - * @param deep_search Perform search recursively - * @return zpl_adt_node * node - */ -ADT_Node* adt_find( ADT_Node* node, char const* name, b32 deep_search ); - -/** - * @brief Allocate an unitialised node within a container at a specified index. - * - * @param parent - * @param index - * @return zpl_adt_node * node - */ -ADT_Node* adt_alloc_at( ADT_Node* parent, ssize index ); - -/** - * @brief Allocate an unitialised node within a container. - * - * @param parent - * @return zpl_adt_node * node - */ -ADT_Node* adt_alloc( ADT_Node* parent ); - -/** - * @brief Move an existing node to a new container at a specified index. - * - * @param node - * @param new_parent - * @param index - * @return zpl_adt_node * node - */ -ADT_Node* adt_move_node_at( ADT_Node* node, ADT_Node* new_parent, ssize index ); - -/** - * @brief Move an existing node to a new container. - * - * @param node - * @param new_parent - * @return zpl_adt_node * node - */ -ADT_Node* adt_move_node( ADT_Node* node, ADT_Node* new_parent ); - -/** - * @brief Swap two nodes. - * - * @param node - * @param other_node - * @return - */ -void adt_swap_nodes( ADT_Node* node, ADT_Node* other_node ); - -/** - * @brief Remove node from container. - * - * @param node - * @return - */ -void adt_remove_node( ADT_Node* node ); - -/** - * @brief Initialise a node as an object - * - * @param obj - * @param name - * @param backing - * @return - */ -b8 adt_set_obj( ADT_Node* obj, char const* name, AllocatorInfo backing ); - -/** - * @brief Initialise a node as an array - * - * @param obj - * @param name - * @param backing - * @return - */ -b8 adt_set_arr( ADT_Node* obj, char const* name, AllocatorInfo backing ); - -/** - * @brief Initialise a node as a string - * - * @param obj - * @param name - * @param value - * @return - */ -b8 adt_set_str( ADT_Node* obj, char const* name, char const* value ); - -/** - * @brief Initialise a node as a float - * - * @param obj - * @param name - * @param value - * @return - */ -b8 adt_set_flt( ADT_Node* obj, char const* name, f64 value ); - -/** - * @brief Initialise a node as a signed integer - * - * @param obj - * @param name - * @param value - * @return - */ -b8 adt_set_int( ADT_Node* obj, char const* name, s64 value ); - -/** - * @brief Append a new node to a container as an object - * - * @param parent - * @param name - * @return* - */ -ADT_Node* adt_append_obj( ADT_Node* parent, char const* name ); - -/** - * @brief Append a new node to a container as an array - * - * @param parent - * @param name - * @return* - */ -ADT_Node* adt_append_arr( ADT_Node* parent, char const* name ); - -/** - * @brief Append a new node to a container as a string - * - * @param parent - * @param name - * @param value - * @return* - */ -ADT_Node* adt_append_str( ADT_Node* parent, char const* name, char const* value ); - -/** - * @brief Append a new node to a container as a float - * - * @param parent - * @param name - * @param value - * @return* - */ -ADT_Node* adt_append_flt( ADT_Node* parent, char const* name, f64 value ); - -/** - * @brief Append a new node to a container as a signed integer - * - * @param parent - * @param name - * @param value - * @return* - */ -ADT_Node* adt_append_int( ADT_Node* parent, char const* name, s64 value ); - -/* parser helpers */ - -/** - * @brief Parses a text and stores the result into an unitialised node. - * - * @param node - * @param base - * @return* - */ -char* adt_parse_number( ADT_Node* node, char* base ); - -/** - * @brief Parses a text and stores the result into an unitialised node. - * This function expects the entire input to be a number. - * - * @param node - * @param base - * @return* - */ -char* adt_parse_number_strict( ADT_Node* node, char* base_str ); - -/** - * @brief Parses and converts an existing string node into a number. - * - * @param node - * @return - */ -ADT_Error adt_c_str_to_number( ADT_Node* node ); - -/** - * @brief Parses and converts an existing string node into a number. - * This function expects the entire input to be a number. - * - * @param node - * @return - */ -ADT_Error adt_c_str_to_number_strict( ADT_Node* node ); - -/** - * @brief Prints a number into a file stream. - * - * The provided file handle can also be a memory mapped stream. - * - * @see zpl_file_stream_new - * @param file - * @param node - * @return - */ -ADT_Error adt_print_number( FileInfo* file, ADT_Node* node ); - -/** - * @brief Prints a string into a file stream. - * - * The provided file handle can also be a memory mapped stream. - * - * @see zpl_file_stream_new - * @param file - * @param node - * @param escaped_chars - * @param escape_symbol - * @return - */ -ADT_Error adt_print_string( FileInfo* file, ADT_Node* node, char const* escaped_chars, char const* escape_symbol ); - -#pragma endregion ADT - -#pragma region CSV - -enum CSV_Error : u32 -{ - ECSV_Error__NONE, - ECSV_Error__INTERNAL, - ECSV_Error__UNEXPECTED_END_OF_INPUT, - ECSV_Error__MISMATCHED_ROWS, -}; - -typedef ADT_Node CSV_Object; - -u8 csv_parse( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header ); -u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header, char delim ); -void csv_free( CSV_Object* obj ); - -void csv_write( FileInfo* file, CSV_Object* obj ); -StrBuilder csv_write_string( AllocatorInfo a, CSV_Object* obj ); -void csv_write_delimiter( FileInfo* file, CSV_Object* obj, char delim ); -StrBuilder csv_write_strbuilder_delimiter( AllocatorInfo a, CSV_Object* obj, char delim ); - -/* inline */ - -inline -u8 csv_parse( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header ) -{ - return csv_parse_delimiter( root, text, allocator, has_header, ',' ); -} - -inline -void csv_write( FileInfo* file, CSV_Object* obj ) -{ - csv_write_delimiter( file, obj, ',' ); -} - -inline -StrBuilder csv_write_string( AllocatorInfo a, CSV_Object* obj ) -{ - return csv_write_strbuilder_delimiter( a, obj, ',' ); -} - -#pragma endregion CSV - #pragma region Scanner // This is a simple file reader that reads the entire file into memory. diff --git a/Project/Source/GasaGen/gen.builder.cpp b/Project/Source/GasaGen/gen.builder.cpp index 1cdcac5..6bbdee2 100644 --- a/Project/Source/GasaGen/gen.builder.cpp +++ b/Project/Source/GasaGen/gen.builder.cpp @@ -39,7 +39,9 @@ Builder builder_open( char const* path ) return result; } - result.Buffer = strbuilder_make_reserve( _ctx->Allocator_Temp, _ctx->InitSize_BuilderBuffer ); + Context* ctx = get_context(); + GEN_ASSERT_NOT_NULL(ctx); + result.Buffer = strbuilder_make_reserve( ctx->Allocator_Temp, ctx->InitSize_BuilderBuffer ); // log_fmt("$Builder - Opened file: %s\n", result.File.filename ); return result; diff --git a/Project/Source/GasaGen/gen.cpp b/Project/Source/GasaGen/gen.cpp index b5e9341..0cd6668 100644 --- a/Project/Source/GasaGen/gen.cpp +++ b/Project/Source/GasaGen/gen.cpp @@ -3403,6 +3403,10 @@ void deinit(Context* ctx) -- context_counter; } +Context* get_context() { + return _ctx; +} + void reset(Context* ctx) { s32 index = 0; diff --git a/Project/Source/GasaGen/gen.dep.hpp b/Project/Source/GasaGen/gen.dep.hpp index b44ca0f..5b7a5e3 100644 --- a/Project/Source/GasaGen/gen.dep.hpp +++ b/Project/Source/GasaGen/gen.dep.hpp @@ -883,7 +883,7 @@ template mem_ptr_const to_mem_ptr_const( Type ptr ) { return (mem // NOTE: Things that shouldn't happen with a message! #define GEN_PANIC( msg, ... ) GEN_ASSERT_MSG( 0, msg, ##__VA_ARGS__ ) -#if GEN_BULD_DEBUG +#if GEN_BUILD_DEBUG #define GEN_FATAL( ... ) \ do \ { \ diff --git a/Project/Source/GasaGen/gen.hpp b/Project/Source/GasaGen/gen.hpp index 529ca23..5a07e8b 100644 --- a/Project/Source/GasaGen/gen.hpp +++ b/Project/Source/GasaGen/gen.hpp @@ -886,7 +886,7 @@ inline TokType str_to_toktype( Str str ) enum TokFlags : u32 { - TF_Operator = bit(0), + TF_Operator = bit(0), TF_Assign = bit(1), TF_Preprocess = bit(2), TF_Preprocess_Cond = bit(3), @@ -3980,6 +3980,9 @@ GEN_API void init(Context* ctx); // However on Windows at least, it doesn't need to occur as the OS will clean up after the process. GEN_API void deinit(Context* ctx); +// Retrieves the active context (not usually needed, but here in case...) +GEN_API Context* get_contex(); + // Clears the allocations, but doesn't free the memoery, then calls init() again. // Ease of use. GEN_API void reset(Context* ctx);