Lumenarium/meta/foldhaus_meta.cpp

356 lines
13 KiB
C++
Raw Normal View History

//
2020-01-21 05:11:07 +00:00
// File: foldhaus_meta.cpp
// Author: Peter Slattery
// Creation Date: 2020-01-19
//
2020-01-21 05:11:07 +00:00
#ifndef FOLDHAUS_META_CPP
#include "gs_meta.cpp"
#include "gs_meta_typeinfo_generator.h"
internal void
GenerateNodeMetaInfo (gsm_code_generator* NodeTypeGen, string_builder* NodeSpecificationGen, string_builder* CallNodeProcGen, gs_meta_preprocessor Meta)
{
2020-01-21 05:11:07 +00:00
// TODO(Peter): Create a FilterTypesByTag function to create a contiguous array
// of type_definition**
WriteF(NodeSpecificationGen, "static node_specification_ NodeSpecifications[] = {\n");
WriteF(CallNodeProcGen, "void CallNodeProc(node_type Type, u8* NodeData)\n{\n");
WriteF(CallNodeProcGen, " switch(Type) { \n");
for (u32 b = 0; b < Meta.TypeTable.TypeBucketsCount; b++)
2020-01-21 05:11:07 +00:00
{
type_table_hash_bucket Bucket = Meta.TypeTable.Types[b];
for (u32 i = 0; i < TYPE_TABLE_BUCKET_MAX; i++)
2020-01-21 05:11:07 +00:00
{
if (Bucket.Keys[i] == 0) { continue; }
2020-01-21 05:11:07 +00:00
type_definition* Decl = Bucket.Values + i;
if (HasTag(MakeStringLiteral("node_proc"), Decl->MetaTags, Meta.TypeTable) &&
Decl->Type == TypeDef_Function)
2020-01-21 05:11:07 +00:00
{
if (Decl->Function.Parameters.Used > 1)
{
WriteF(CallNodeProcGen, "ERROR: Procedure tagged with node_proc has more than one parameter\n");
continue;
}
AddEnumElement(NodeTypeGen, Decl->Identifier);
variable_decl* Param = Decl->Function.Parameters.GetElementAtIndex(0);
type_table_handle ParamTypeHandle = Param->TypeHandle;
type_definition* ParamType = GetTypeDefinition(ParamTypeHandle, Meta.TypeTable);
type_table_handle ReturnTypeHandle = Decl->Function.ReturnTypeHandle;
type_definition* ReturnType = GetTypeDefinition(ReturnTypeHandle, Meta.TypeTable);
WriteF(NodeSpecificationGen, "{ NodeType_%S, {\"%S\", %d}, gsm_StructType_%S }, \n",
Decl->Identifier,
Decl->Identifier,
Decl->Identifier.Length,
ParamType->Identifier);
WriteF(CallNodeProcGen, " case NodeType_%.*s:\n", StringExpand(Decl->Identifier));
WriteF(CallNodeProcGen, " {\n");
WriteF(CallNodeProcGen, " %.*s(", StringExpand(Decl->Identifier));
WriteF(CallNodeProcGen, "(%.*s*)NodeData", StringExpand(ParamType->Identifier));
WriteF(CallNodeProcGen, ");\n");
WriteF(CallNodeProcGen, " } break;\n");
2020-01-21 05:11:07 +00:00
}
}
}
WriteF(CallNodeProcGen, " }\n");
WriteF(CallNodeProcGen, "}\n\n");
2020-01-21 05:11:07 +00:00
WriteF(NodeSpecificationGen, "};\n\n");
FinishEnumGeneration(NodeTypeGen);
}
struct panel_elements
{
string PanelIdentifier;
type_table_handle InitProcDecl;
type_table_handle CleanupProcDecl;
type_table_handle RenderProcDecl;
type_table_handle PanelCommandsStruct;
};
internal b32
StringIsPrefixedBy (string Prefix, string TestString)
{
b32 Result = false;
if (TestString.Length >= Prefix.Length)
{
Result = true;
for (s32 i = 0; i < Prefix.Length; i++)
{
if (Prefix.Memory[i] != TestString.Memory[i])
{
Result = false;
break;
}
}
}
return Result;
}
internal void
AttemptPlacePanelProc(type_table_handle ProcHandle, type_table TypeTable, gs_bucket<panel_elements>* Panels)
{
string InitProcTag = MakeStringLiteral("panel_init");
string CleanupProcTag = MakeStringLiteral("panel_cleanup");
string RenderProcTag = MakeStringLiteral("panel_render");
string PanelTypePrefix = MakeStringLiteral("panel_type_");
type_definition* Decl = GetTypeDefinition(ProcHandle, TypeTable);
meta_tag* PanelTypeTag = 0;
for (u32 i = 0; i < Decl->MetaTags.Used; i++)
{
type_table_handle MetaTagHandle = *Decl->MetaTags.GetElementAtIndex(i);
meta_tag* MetaTag = GetMetaTag(MetaTagHandle, TypeTable);
if (StringIsPrefixedBy(PanelTypePrefix, MetaTag->Identifier))
{
PanelTypeTag = MetaTag;
break;
}
}
if (PanelTypeTag != 0)
{
s32 PanelIndex = -1;
for (u32 i = 0; i < Panels->Used; i++)
{
panel_elements* Panel = Panels->GetElementAtIndex(i);
if (StringsEqual(Panel->PanelIdentifier, PanelTypeTag->Identifier))
{
PanelIndex = (s32)i;
break;
}
}
if (PanelIndex < 0)
{
panel_elements NewPanel = {0};
NewPanel.PanelIdentifier = PanelTypeTag->Identifier;
PanelIndex = Panels->PushElementOnBucket(NewPanel);
}
Assert(PanelIndex >= 0);
panel_elements* PanelElements = Panels->GetElementAtIndex(PanelIndex);
if (HasTag(InitProcTag, Decl->MetaTags, TypeTable))
{
PanelElements->InitProcDecl = ProcHandle;
}
else if (HasTag(CleanupProcTag, Decl->MetaTags, TypeTable))
{
PanelElements->CleanupProcDecl = ProcHandle;
}
else if (HasTag(RenderProcTag, Decl->MetaTags, TypeTable))
{
PanelElements->RenderProcDecl = ProcHandle;
}
}
}
internal void
AttemptPlacePanelCommands(type_table_handle StructHandle, type_table TypeTable, gs_bucket<panel_elements>* Panels)
{
string CommandsTag = MakeStringLiteral("panel_commands");
type_definition* Decl = GetTypeDefinition(StructHandle, TypeTable);
if (HasTag(CommandsTag, Decl->MetaTags, TypeTable))
{
for (u32 i = 0; i < Decl->MetaTags.Used; i++)
{
type_table_handle MetaTagHandle = *Decl->MetaTags.GetElementAtIndex(i);
meta_tag* MetaTag = GetMetaTag(MetaTagHandle, TypeTable);
printf("%.*s, ", StringExpand(MetaTag->Identifier));
}
printf("\n");
}
}
internal void
MakeReadableIdentifier(string* Identifier)
{
for (s32 i = 0; i < Identifier->Length; i++)
{
char At = Identifier->Memory[i];
if (At == '_')
{
Identifier->Memory[i] = ' ';
}
else if (IsAlpha(At) && (i == 0 || IsWhitespace(Identifier->Memory[i - 1])))
{
Identifier->Memory[i] = ToUpper(At);
}
}
}
internal void
GeneratePanelMetaInfo(gs_meta_preprocessor Meta, string_builder* PanelEnumGen, string_builder* PanelCodeGen)
{
gs_bucket<panel_elements> Panels = {0};
for (u32 b = 0; b < Meta.TypeTable.TypeBucketsCount; b++)
{
type_table_hash_bucket Bucket = Meta.TypeTable.Types[b];
for (u32 i = 0; i < TYPE_TABLE_BUCKET_MAX; i++)
{
if (Bucket.Keys[i] == 0) { continue; }
type_table_handle DeclHandle = {(s32)b, i};
type_definition* Decl = Bucket.Values + i;
if (Decl->Type == TypeDef_Function)
{
AttemptPlacePanelProc(DeclHandle, Meta.TypeTable, &Panels);
}
else if (Decl->Type == TypeDef_Struct)
{
AttemptPlacePanelCommands(DeclHandle, Meta.TypeTable, &Panels);
}
}
}
WriteF(PanelEnumGen, "enum panel_type {\n");
WriteF(PanelCodeGen, "global_variable s32 GlobalPanelDefsCount = %d;\n", Panels.Used);
WriteF(PanelCodeGen, "global_variable panel_definition GlobalPanelDefs[] = {\n");
for (u32 i = 0; i < Panels.Used; i++)
{
panel_elements* Panel = Panels.GetElementAtIndex(i);
string PanelIdentifier = {0};
PanelIdentifier.Max = Panel->PanelIdentifier.Length;
PanelIdentifier.Memory = (char*)malloc(sizeof(char) * PanelIdentifier.Max);
CopyStringTo(Substring(Panel->PanelIdentifier, 11), &PanelIdentifier);
MakeReadableIdentifier(&PanelIdentifier);
type_definition* InitDecl = GetTypeDefinition(Panel->InitProcDecl, Meta.TypeTable);
type_definition* CleanupDecl = GetTypeDefinition(Panel->CleanupProcDecl, Meta.TypeTable);
type_definition* RenderDecl = GetTypeDefinition(Panel->RenderProcDecl, Meta.TypeTable);
WriteF(PanelCodeGen, "{ \"%S\", %d, ", PanelIdentifier, PanelIdentifier.Length);
WriteF(PanelCodeGen, "%S, ", InitDecl->Identifier);
WriteF(PanelCodeGen, "%S, ", CleanupDecl->Identifier);
WriteF(PanelCodeGen, "%S, ", RenderDecl->Identifier);
// TODO(Peter): This is a shortcut cause I'm being lazy. We arent' putting arrays into the
// AST when we parse our codebase so there's no way to tag the array of Commands for each
// panel for use here. Instead, I'm just requiring that the array be of the form
// <panel_name_base>_Commands where panel_name_base is whatever the Init function is called
// minus _Input. So for example, if you have ScupltureView_Init, then the panel_name_base is
// SculptureView and the commands array must be called SculptureView_Commands.
// Ideally we actually go through and parse these arrays.
string InitSuffix = MakeStringLiteral("_Init");
string PanelNameBase = Substring(InitDecl->Identifier, 0, InitDecl->Identifier.Length - InitSuffix.Length);
WriteF(PanelCodeGen, "%S_Commands, ", PanelNameBase);
WriteF(PanelCodeGen, "%S_CommandsCount ", PanelNameBase);
WriteF(PanelEnumGen, "PanelType_%S,\n", PanelNameBase);
WriteF(PanelCodeGen, "},\n");
}
WriteF(PanelCodeGen, "};\n");
WriteF(PanelEnumGen, "};\n");
}
internal string
AllocAndConcatStrings(string First, string Second)
{
string Result = {0};
Result.Max = First.Length + Second.Length + 1;
Result.Memory = (char*)malloc(sizeof(char) * Result.Max);
ConcatString(First, &Result);
ConcatString(Second, &Result);
NullTerminate(&Result);
Result.Length -= 1;
return Result;
}
int main(int ArgCount, char* Args[])
{
if (ArgCount <= 1)
{
printf("Please supply at least one source directory to analyze.\n");
return 0;
}
string RootFile = MakeString(Args[1]);
s32 IndexOfLastSlash = ReverseSearchForCharInSet(RootFile, "\\/");
string WorkingDirectory = Substring(RootFile, 0, IndexOfLastSlash + 1);
string GeneratedDirectoryName = MakeStringLiteral("generated\\");
string GeneratedFilesDirectory = AllocAndConcatStrings(WorkingDirectory, GeneratedDirectoryName);
printf("Putting Generated Files In %s\n", GeneratedFilesDirectory.Memory);
gs_meta_preprocessor Meta = PreprocessProgram(Args[1]);
typeinfo_generator TypeGenerator = InitTypeInfoGenerator(Meta.TypeTable);
GenerateMetaTagList(Meta.TypeTable, &TypeGenerator);
GenerateFilteredTypeInfo(MakeStringLiteral("node_struct"), Meta.TypeTable, &TypeGenerator);
GenerateFilteredTypeInfo(MakeStringLiteral("gen_type_info"), Meta.TypeTable, &TypeGenerator);
FinishGeneratingTypes(&TypeGenerator);
gsm_code_generator NodeTypeGen = BeginEnumGeneration("node_type", "NodeType", false, true);
string_builder NodeSpecificationGen = {0};
string_builder CallNodeProcGen = {0};
GenerateNodeMetaInfo(&NodeTypeGen, &NodeSpecificationGen, &CallNodeProcGen, Meta);
string_builder PanelEnumGen = {0};
string_builder PanelCodeGen = {0};
GeneratePanelMetaInfo(Meta, &PanelEnumGen, &PanelCodeGen);
2020-01-21 05:11:07 +00:00
string TypeInfoHFilePath = AllocAndConcatStrings(GeneratedFilesDirectory, MakeStringLiteral("gs_meta_generated_typeinfo.h"));
FILE* TypeInfoH = fopen(TypeInfoHFilePath.Memory, "w");
if (TypeInfoH)
{
WriteStringBuilderToFile(TypeGenerator.MetaTagEnum, TypeInfoH);
WriteStringBuilderToFile(TypeGenerator.MetaTagString, TypeInfoH);
2020-01-21 05:11:07 +00:00
WriteStringBuilderToFile(*TypeGenerator.TypeList.Builder, TypeInfoH);
WriteStringBuilderToFile(TypeGenerator.StructMembers, TypeInfoH);
WriteStringBuilderToFile(TypeGenerator.TypeDefinitions, TypeInfoH);
2020-01-20 01:03:19 +00:00
fclose(TypeInfoH);
}
else
{
printf("Error: Unable to open file at %.*s\n", StringExpand(TypeInfoHFilePath));
}
string NodeInfoHFilePath = AllocAndConcatStrings(GeneratedFilesDirectory, MakeStringLiteral("foldhaus_nodes_generated.h"));
FILE* NodeInfoH = fopen(NodeInfoHFilePath.Memory, "w");
2020-01-21 05:11:07 +00:00
if (NodeInfoH)
{
WriteStringBuilderToFile(*NodeTypeGen.Builder, NodeInfoH);
WriteStringBuilderToFile(NodeSpecificationGen, NodeInfoH);
WriteStringBuilderToFile(CallNodeProcGen, NodeInfoH);
2020-01-21 05:11:07 +00:00
fclose(NodeInfoH);
}
else
{
printf("Error: Unable to open file at %.*s\n", StringExpand(NodeInfoHFilePath));
}
2020-01-21 05:11:07 +00:00
string PanelInfoHFilePath = AllocAndConcatStrings(GeneratedFilesDirectory, MakeStringLiteral("foldhaus_panels_generated.h"));
FILE* PanelInfoH = fopen(PanelInfoHFilePath.Memory, "w");
if (PanelInfoH)
{
WriteStringBuilderToFile(PanelEnumGen, PanelInfoH);
WriteStringBuilderToFile(PanelCodeGen, PanelInfoH);
fclose(PanelInfoH);
}
else
{
printf("Error: Unable to open file at %.*s\n", StringExpand(PanelInfoHFilePath));
}
FinishMetaprogram(&Meta);
//__debugbreak();
2019-10-30 14:28:02 +00:00
return 0;
2020-01-21 05:11:07 +00:00
}
#define FOLDHAUS_META_CPP
#endif // FOLDHAUS_META_CPP