diff --git a/meta/foldhaus_meta.cpp b/meta/foldhaus_meta.cpp index 10b6a16..bb48e5d 100644 --- a/meta/foldhaus_meta.cpp +++ b/meta/foldhaus_meta.cpp @@ -10,1473 +10,9 @@ // that point in processing the file // TODO: specify which stage you want it to break at -#include -#include -#include -#include -#include "..\src\gs_platform.h" -#include -#include -#include - -#include "gs_meta_lexer.h" - -struct error_buffer -{ - char* Backbuffer; - string* Contents; -}; - -#define ERROR_MAX_LENGTH 256 -#define ERROR_BUFFER_SIZE 256 -struct errors -{ - error_buffer* Buffers; - u32 BuffersCount; - u32 Used; -}; - -internal void -PushFError (errors* Errors, char* Format, ...) -{ - if (Errors->Used >= (Errors->BuffersCount * ERROR_BUFFER_SIZE)) - { - Errors->BuffersCount += 1; - Errors->Buffers = (error_buffer*)realloc(Errors->Buffers, sizeof(error_buffer*) * Errors->BuffersCount); - - error_buffer* NewBuffer = Errors->Buffers + (Errors->BuffersCount - 1); - NewBuffer->Backbuffer = (char*)malloc(sizeof(char) * ERROR_MAX_LENGTH * ERROR_BUFFER_SIZE); - NewBuffer->Contents = (string*)malloc(sizeof(string) * ERROR_BUFFER_SIZE); - - for (u32 i = 0; i < ERROR_BUFFER_SIZE; i++) - { - NewBuffer->Contents[i].Memory = NewBuffer->Backbuffer + (i * ERROR_MAX_LENGTH); - NewBuffer->Contents[i].Max = ERROR_MAX_LENGTH; - NewBuffer->Contents[i].Length = 0; - } - } - - u32 NewErrorIndex = Errors->Used++; - u32 BufferIndex = NewErrorIndex / ERROR_BUFFER_SIZE; - u32 IndexInBuffer = NewErrorIndex % ERROR_BUFFER_SIZE; - string* NewError = Errors->Buffers[BufferIndex].Contents + IndexInBuffer; - - va_list Args; - va_start(Args, Format); - NewError->Length = PrintFArgsList(NewError->Memory, NewError->Max, Format, Args); - va_end(Args); -} - -internal string* -TakeError (errors* Errors) -{ - u32 NewErrorIndex = Errors->Used++; - u32 BufferIndex = NewErrorIndex / ERROR_BUFFER_SIZE; - u32 IndexInBuffer = NewErrorIndex % ERROR_BUFFER_SIZE; - string* NewError = Errors->Buffers[BufferIndex].Contents + IndexInBuffer; - return NewError; -} - -internal void -PrintAllErrors (errors Errors) -{ - for (u32 i = 0; i < Errors.Used; i++) - { - u32 BufferIndex = i / ERROR_BUFFER_SIZE; - u32 IndexInBuffer = i % ERROR_BUFFER_SIZE; - string Error = Errors.Buffers[BufferIndex].Contents[IndexInBuffer]; - printf("%.*s\n", StringExpand(Error)); - } -} - -#include "foldhaus_meta_type_table.h" - -PLATFORM_ALLOC(StdAlloc) -{ - u8* Result = (u8*)malloc(Size); - return Result; -} - -struct source_code_file -{ - string Path; - s32 FileSize; - string Contents; - - s32 FirstTokenIndex; - s32 LastTokenIndex; -}; - -struct token_iter -{ - gs_bucket* Tokens; - token* TokenAt; - s32 TokenAtIndex; - s32 FirstToken; - s32 LastToken; - -#define TOKEN_ITER_SNAPSHOTS_MAX 64 - u32 SnapshotsUsed; - u32 Snapshots[TOKEN_ITER_SNAPSHOTS_MAX]; - - errors* Errors; -}; - -internal token* -NextToken (token_iter* Iter) -{ - if (Iter->TokenAtIndex < Iter->LastToken) - { - Iter->TokenAtIndex++; - Iter->TokenAt = Iter->Tokens->GetElementAtIndex(Iter->TokenAtIndex); - } - - return Iter->TokenAt; -} - -internal b32 -TokenAtEquals(token_iter* Iter, char* String) -{ - b32 Result = false; - if (StringEqualsCharArray(Iter->TokenAt->Text, String)) - { - Result = true; - NextToken(Iter); - } - return Result; -} - -internal b32 -TokenAtEquals(token_iter* Iter, token_type Type) -{ - b32 Result = false; - if (Iter->TokenAt->Type == Type) - { - Result = true; - NextToken(Iter); - } - return Result; -} - -internal b32 -TokenAtEquals(token_iter* Iter, token_type Type, token* Token) -{ - b32 Result = false; - if (Iter->TokenAt->Type == Type) - { - Result = true; - *Token = *Iter->TokenAt; - NextToken(Iter); - } - return Result; -} - -internal void -PushSnapshot (token_iter* Iter) -{ - Iter->Snapshots[Iter->SnapshotsUsed++] = Iter->TokenAtIndex; -} - -internal void -PopSnapshot (token_iter* Iter) -{ - if (Iter->SnapshotsUsed > 0) - { - Iter->SnapshotsUsed -= 1; - } -} - -internal void -ApplySnapshot (token_iter* Iter) -{ - u32 SnapshotIndex = Iter->SnapshotsUsed; - u32 SnapshotPoint = Iter->Snapshots[SnapshotIndex]; - Iter->TokenAtIndex = SnapshotPoint; - Iter->TokenAt = Iter->Tokens->GetElementAtIndex(SnapshotPoint); -} - -internal void -ApplySnapshotIfNotParsedAndPop(b32 ParseSuccess, token_iter* Iter) -{ - PopSnapshot(Iter); - if (!ParseSuccess) - { - ApplySnapshot(Iter); - } -} - - -internal s32 -GetFileSize (char* FileName) -{ - s32 Result = 0; - - FILE* ReadFile = fopen(FileName, "r"); - if (ReadFile) - { - fseek(ReadFile, 0, SEEK_END); - size_t FileSize = ftell(ReadFile); - fseek(ReadFile, 0, SEEK_SET); - - Result = (s32)FileSize; - fclose(ReadFile); - } - - return Result; -} - -internal s32 -ReadEntireFileAndNullTerminate (source_code_file* File, errors* Errors) -{ - s32 LengthRead = 0; - - FILE* ReadFile = fopen(File->Path.Memory, "r"); - if (ReadFile) - { - fseek(ReadFile, 0, SEEK_END); - size_t FileSize = ftell(ReadFile); - fseek(ReadFile, 0, SEEK_SET); - - Assert(File->Contents.Memory == 0); - File->Contents.Max = (s32)FileSize + 1; - File->Contents.Memory = (char*)malloc(File->Contents.Max); - - size_t ReadSize = fread(File->Contents.Memory, 1, FileSize, ReadFile); - File->Contents.Memory[FileSize] = 0; - File->Contents.Length = (s32)ReadSize; - - LengthRead = (s32)ReadSize + 1; - fclose(ReadFile); - } - else - { - PushFError(Errors, "Could Not Read File: %S", File->Path); - } - - return LengthRead; -} - -internal b32 -FileAlreadyInSource(string Path, gs_bucket SourceFiles) -{ - b32 Result = false; - - for (u32 i = 0; i < SourceFiles.Used; i++) - { - source_code_file* File = SourceFiles.GetElementAtIndex(i); - if (StringsEqual(File->Path, Path)) - { - Result = true; - break; - } - } - - return Result; -} - -internal s64 -GetWallClock () -{ - LARGE_INTEGER Time; - if (!QueryPerformanceCounter(&Time)) - { - s32 Error = GetLastError(); - InvalidCodePath; - } - return (s64)Time.QuadPart; -} - -internal s64 -GetPerformanceFrequency () -{ - LARGE_INTEGER Frequency; - if (!QueryPerformanceFrequency(&Frequency)) - { - s32 Error = GetLastError(); - InvalidCodePath; - } - return (s64)Frequency.QuadPart; -} - -internal r32 -GetSecondsElapsed(s64 StartCycles, s64 EndCycles) -{ - s64 Frequency = GetPerformanceFrequency(); - r32 SecondsElapsed = (r32)(EndCycles - StartCycles) / (r32)(Frequency); - return SecondsElapsed; -} - -internal void -AddFileToSource(string RelativePath, gs_bucket* SourceFiles, errors* Errors) -{ - source_code_file File = {0}; - - File.FirstTokenIndex = -1; - File.LastTokenIndex = -1; - - u32 PathLength = RelativePath.Length + 1; - File.Path = MakeString((char*)malloc(sizeof(char) * PathLength), 0, PathLength); - CopyStringTo(RelativePath, &File.Path); - NullTerminate(&File.Path); - - File.FileSize = ReadEntireFileAndNullTerminate(&File, Errors); - - if (File.FileSize > 0) - { - SourceFiles->PushElementOnBucket(File); - } - else - { - PushFError(Errors, "Error: Could not load file %S\n", RelativePath); - } -} - -internal void -TokenizeFile (source_code_file* File, gs_bucket* Tokens) -{ - tokenizer Tokenizer = {}; - Tokenizer.At = File->Contents.Memory; - Tokenizer.Memory = File->Contents.Memory; - Tokenizer.MemoryLength = File->Contents.Max; - - token* LastToken = 0; - while(AtValidPosition(Tokenizer)) - { - token NewToken = GetNextToken(&Tokenizer); - u32 TokenIndex = Tokens->PushElementOnBucket(NewToken); - if (File->FirstTokenIndex < 0) - { - File->FirstTokenIndex = (s32)TokenIndex; - } - } - - File->LastTokenIndex = Tokens->Used - 1; -} - -internal b32 -ParseMetaTag(token_iter* Iter, gs_bucket* TagList) -{ - b32 Result = false; - PushSnapshot(Iter); - - if (TokenAtEquals(Iter, "GSMetaTag") && - TokenAtEquals(Iter, "(")) - { - token MetaIdentifier = {0}; - if (TokenAtEquals(Iter, Token_Identifier, &MetaIdentifier)) - { - TagList->PushElementOnBucket(MetaIdentifier); - if (StringsEqual(MetaIdentifier.Text, MakeStringLiteral("breakpoint"))) - { - // NOTE(Peter): This is not a temporary breakpoint. It is - // used to be able to break the meta program at specific points - // throughout execution - __debugbreak(); - } - - if (TokenAtEquals(Iter, ")") && - TokenAtEquals(Iter, ";")) - { - Result = true; - } - } - } - - ApplySnapshotIfNotParsedAndPop(Result, Iter); - return Result; -} - -internal b32 -ShortInt (token_iter* Iter, s32* TypeIndexOut, type_table TypeTable) -{ - b32 Result = false; - PushSnapshot(Iter); - - if (TokenAtEquals(Iter, "unsigned") || - TokenAtEquals(Iter, "signed")) - { - } - - if (TokenAtEquals(Iter, "short")) - { - Result = true; - if (TokenAtEquals(Iter, "int")) - { - Result = true; - } - } - - ApplySnapshotIfNotParsedAndPop(Result, Iter); - if (Result) - { - *TypeIndexOut = GetIndexOfType(MakeStringLiteral("short int"), TypeTable); - } - return Result; -} - -internal b32 -Int (token_iter* Iter, s32* TypeIndexOut, type_table TypeTable) -{ - b32 Result = false; - PushSnapshot(Iter); - - if (TokenAtEquals(Iter, "unsigned") || - TokenAtEquals(Iter, "signed")) - { - } - - if (TokenAtEquals(Iter, "int")) - { - Result = true; - } - - ApplySnapshotIfNotParsedAndPop(Result, Iter); - if (Result) - { - *TypeIndexOut = GetIndexOfType(MakeStringLiteral("int"), TypeTable); - } - return Result; -} - -internal b32 -LongInt (token_iter* Iter, s32* TypeIndexOut, type_table TypeTable) -{ - b32 Result = false; - PushSnapshot(Iter); - - if (TokenAtEquals(Iter, "unsigned") || - TokenAtEquals(Iter, "signed")) - { - } - - if (TokenAtEquals(Iter, "long")) - { - Result = true; - if (TokenAtEquals(Iter, "int")) - { - Result = true; - } - } - - ApplySnapshotIfNotParsedAndPop(Result, Iter); - if (Result) - { - *TypeIndexOut = GetIndexOfType(MakeStringLiteral("long int"), TypeTable); - } - return Result; -} - -internal b32 -LongLongInt (token_iter* Iter, s32* TypeIndexOut, type_table TypeTable) -{ - b32 Result = false; - PushSnapshot(Iter); - - if (TokenAtEquals(Iter, "unsigned") || - TokenAtEquals(Iter, "signed")) - { - - } - - if (TokenAtEquals(Iter, "long")) - { - if (TokenAtEquals(Iter, "long")) - { - Result = true; - if (TokenAtEquals(Iter, "int")) - { - Result = true; - } - } - } - - ApplySnapshotIfNotParsedAndPop(Result, Iter); - if (Result) - { - *TypeIndexOut = GetIndexOfType(MakeStringLiteral("long long int"), TypeTable); - } - return Result; -} - -internal b32 -ParseChar(token_iter* Iter, s32* TypeIndexOut, type_table TypeTable) -{ - b32 Result = false; - PushSnapshot(Iter); - - if (TokenAtEquals(Iter, "unsigned") || - TokenAtEquals(Iter, "signed")) - { - - } - - if (TokenAtEquals(Iter, "char")) - { - Result = true; - } - - ApplySnapshotIfNotParsedAndPop(Result, Iter); - if (Result) - { - *TypeIndexOut = GetIndexOfType(MakeStringLiteral("char"), TypeTable); - } - return Result; -} - -internal b32 -ParseBool(token_iter* Iter, s32* TypeIndexOut, type_table TypeTable) -{ - b32 Result = false; - PushSnapshot(Iter); - - if (TokenAtEquals(Iter, "bool")) - { - Result = true; - *TypeIndexOut = GetIndexOfType(MakeStringLiteral("bool"), TypeTable); - } - - ApplySnapshotIfNotParsedAndPop(Result, Iter); - return Result; -} - -internal b32 -ParseFloat(token_iter* Iter, s32* TypeIndexOut, type_table TypeTable) -{ - b32 Result = false; - PushSnapshot(Iter); - - if (TokenAtEquals(Iter, "float")) - { - Result = true; - *TypeIndexOut= GetIndexOfType(MakeStringLiteral("float"), TypeTable); - } - - ApplySnapshotIfNotParsedAndPop(Result, Iter); - return Result; -} - -internal b32 -ParseDouble(token_iter* Iter, s32* TypeIndexOut, type_table TypeTable) -{ - b32 Result = false; - PushSnapshot(Iter); - - if (TokenAtEquals(Iter, "double")) - { - Result = true; - *TypeIndexOut = GetIndexOfType(MakeStringLiteral("double"), TypeTable); - } - - ApplySnapshotIfNotParsedAndPop(Result, Iter); - return Result; -} - -// :UndeclaredType -// NOTE(Peter): If TypeIndexOut is -1, you need to call NextToken after this -// function to advance past the type identifier. -internal b32 -ParseType(token_iter* Iter, type_table* TypeTable, s32* TypeIndexOut) -{ - b32 Result = false; - *TypeIndexOut = -1; - PushSnapshot(Iter); - - // TODO(Peter): Store signedness, and what makes up a type - if (ParseChar(Iter, TypeIndexOut, *TypeTable)) - { - Result = true; - } - else if (StringsEqual(Iter->TokenAt->Text, MakeStringLiteral("wchar_t"))) - { - NextToken(Iter); - Result = true; - *TypeIndexOut = GetIndexOfType(MakeStringLiteral("wchar_t"), *TypeTable); - } - else if (ParseBool(Iter, TypeIndexOut, *TypeTable)) - { - NextToken(Iter); - Result = true; - } - else if (LongLongInt(Iter, TypeIndexOut, *TypeTable)) - { - Result = true; - } - else if (LongInt(Iter, TypeIndexOut, *TypeTable)) - { - Result = true; - } - else if (ShortInt(Iter, TypeIndexOut, *TypeTable)) - { - Result = true; - } - else if (Int(Iter, TypeIndexOut, *TypeTable)) - { - Result = true; - } - else if (ParseFloat(Iter, TypeIndexOut, *TypeTable)) - { - Result = true; - } - else if (ParseDouble(Iter, TypeIndexOut, *TypeTable)) - { - Result = true; - } - else if (StringsEqual(Iter->TokenAt->Text, MakeStringLiteral("void"))) - { - NextToken(Iter); - Result = true; - *TypeIndexOut = GetIndexOfType(MakeStringLiteral("void"), *TypeTable); - } - else - { - *TypeIndexOut = GetIndexOfType(Iter->TokenAt->Text, *TypeTable); - if (*TypeIndexOut >= 0) - { - Result = true; - NextToken(Iter); - } - else if(Iter->TokenAt->Type == Token_Identifier) - { - Result = true; - // NOTE(Peter): In this case, we believe we are at a type identifier, - // however, it hasn't been declared yet. This is due to the fact that we - // tokenize files, then parse them, then import the files they include, and - // then begin tokenizing, parsing, etc for those files. - // In the case that we get an as-of-yet undeclared type, we leave it - // up to the calling site to determine what to do with that information - // :UndeclaredType - *TypeIndexOut = -1; - } - } - - ApplySnapshotIfNotParsedAndPop(Result, Iter); - return Result; -} - -internal b32 -ParsePointer (token_iter* Iter) -{ - b32 Result = false; - if (TokenAtEquals(Iter, "*")) - { - Result = true; - } - return Result; -} - -internal b32 -ParseConstVolatile (token_iter* Iter) -{ - b32 Result = false; - PushSnapshot(Iter); - - if (TokenAtEquals(Iter, "volatile") || - TokenAtEquals(Iter, "const")) - { - Result = true; - } - - ApplySnapshotIfNotParsedAndPop(Result, Iter); - return Result; -} - -internal b32 -ParseVariableDecl(token_iter* Iter, gs_bucket* TagList, gs_bucket* VariableList, type_table* TypeTable) -{ - b32 Result = false; - PushSnapshot(Iter); - - if (ParseConstVolatile(Iter)) - { - // NOTE(Peter): we don't do anything with this atm - // dont have a reason to just yet - // :UnusedConstVolatile - } - - s32 TypeIndex = -1; - if (ParseType(Iter, TypeTable, &TypeIndex)) - { - // :UndeclaredType - if (TypeIndex < 0) - { - TypeIndex = PushUndeclaredType(Iter->TokenAt->Text, TypeTable); - NextToken(Iter); - } - - b32 IsPointer = ParsePointer(Iter); - - if (ParseConstVolatile(Iter)) - { - // :UnusedConstVolatile - } - - do { - token IdentifierToken = {}; - if (TokenAtEquals(Iter, Token_Identifier, &IdentifierToken)) - { - // Array Notationg ie r32 x[2]; - // NOTE(Peter): True initially because if there is no array notation, we - // are still ok to proceed - b32 ArrayParseSuccess = true; - u32 ArrayCount = 0; - if (TokenAtEquals(Iter, "[")) - { - // NOTE(Peter): Once we get to this point, we have to complete the entire - // array notation before we have successfully parsed, hence setting - // ArrayParseSucces to false here. - ArrayParseSuccess = false; - token NumberToken = {}; - if (TokenAtEquals(Iter, Token_Number, &NumberToken)) - { - parse_result ParseArrayCount = ParseUnsignedInt(StringExpand(NumberToken.Text)); - ArrayCount = ParseArrayCount.UnsignedIntValue; - - if (TokenAtEquals(Iter, "]")) - { - ArrayParseSuccess = true; - } - } - } - - if (ArrayParseSuccess) - { - Result = true; - - variable_decl* Decl = VariableList->TakeElement(); - *Decl = {}; - Decl->Identifier = IdentifierToken.Text; - Decl->TypeIndex = TypeIndex; - Decl->Pointer = IsPointer; - Decl->ArrayCount = ArrayCount; - CopyMetaTagsAndClear(TagList, &Decl->MetaTags); - } - } - } while (TokenAtEquals(Iter, ",")); - } - - ApplySnapshotIfNotParsedAndPop(Result, Iter); - return Result; -} - -internal b32 -StructOrUnion(token_iter* Iter, type_definition_type* Type) -{ - b32 Result = false; - if (TokenAtEquals(Iter, "struct")) - { - Result = true; - *Type = TypeDef_Struct; - } - else if (TokenAtEquals(Iter, "union")) - { - Result = true; - *Type = TypeDef_Union; - } - return Result; -} - -internal b32 -ParseStruct(token_iter* Iter, s32* StructTypeIndexOut, gs_bucket* TagList, type_table* TypeTable) -{ - b32 Result = false; - *StructTypeIndexOut = -1; - - PushSnapshot(Iter); - - type_definition_type DeclType; - if (StructOrUnion(Iter, &DeclType)) - { - token IdentifierToken = {}; - if (TokenAtEquals(Iter, Token_Identifier, &IdentifierToken)) {} - - // TODO(Peter): Handle name coming after the struct - if (TokenAtEquals(Iter, "{")) - { - type_definition StructDecl = {}; - StructDecl.Identifier = IdentifierToken.Text; - StructDecl.Type = DeclType; - CopyMetaTagsAndClear(TagList, &StructDecl.MetaTags); - - while (!TokenAtEquals(Iter, "}")) - { - s32 MemberStructTypeIndex = {}; - variable_decl MemberDecl = {}; - if (ParseMetaTag(Iter, TagList)) - { - - } - else if (ParseVariableDecl(Iter, TagList, &StructDecl.Struct.MemberDecls, TypeTable)) - { - if (!TokenAtEquals(Iter, ";")) - { - PushFError(Iter->Errors, "No semicolon after struct member variable declaration. %S", StructDecl.Identifier); - } - } - else if (ParseStruct(Iter, &MemberStructTypeIndex, TagList, TypeTable)) - { - // NOTE(Peter): Pretty sure, since we just parsed the struct, that - // MemberStructTypeIndex should never be -1 (unknown type). - // Putting this Assert here for now, but remove if there's a valid - // reason that you might not be able to find a struct just parsed at - // this point. - Assert(MemberStructTypeIndex >= 0); - - MemberDecl.TypeIndex = MemberStructTypeIndex; - StructDecl.Struct.MemberDecls.PushElementOnBucket(MemberDecl); - } - else - { - // NOTE(Peter): One of the things that falls through here is - // cpp template stuff. Eventually, we should be able to use - // this meta layer to get rid of them all together, and then - // we can just disallow CPP templates - NextToken(Iter); - } - } - - if (TokenAtEquals(Iter, ";")) - { - Result = true; - *StructTypeIndexOut = PushTypeDefOnTypeTable(StructDecl, TypeTable); - } - } - } - - ApplySnapshotIfNotParsedAndPop(Result, Iter); - return Result; -} - -// ( type *? identifier, ... ) -internal b32 -ParseFunctionParameterList (token_iter* Iter, type_definition* FunctionPtrDecl, gs_bucket* TagList, type_table* TypeTable) -{ - b32 Result = false; - PushSnapshot(Iter); - - if (TokenAtEquals(Iter, "(")) - { - Result = true; - - while(!StringsEqual(Iter->TokenAt->Text, MakeStringLiteral(")"))) - { - if (ParseVariableDecl(Iter, TagList, &FunctionPtrDecl->FunctionPtr.Parameters, TypeTable)) - { - if (TokenAtEquals(Iter, Token_Comma)) - { - } - else if (!StringsEqual(Iter->TokenAt->Text, MakeStringLiteral(")"))) - { - Result = false; - break; - } - } - } - - if (TokenAtEquals(Iter, ")")) - { - Result = true; - } - } - - ApplySnapshotIfNotParsedAndPop(Result, Iter); - return Result; -} - -internal b32 -ParseFunctionDeclaration (token_iter* Iter, token* Identifier, gs_bucket* TagList, type_table* TypeTable) -{ - b32 Result = false; - PushSnapshot(Iter); - - s32 ReturnTypeIndex = -1; - if (ParseType(Iter, TypeTable, &ReturnTypeIndex)) - { - if (ReturnTypeIndex < 0) - { - ReturnTypeIndex = PushUndeclaredType(Iter->TokenAt->Text, TypeTable); - NextToken(Iter); - } - - b32 IsPointer = ParsePointer(Iter); - - if (TokenAtEquals(Iter, Token_Identifier, Identifier)) - { - type_definition FunctionPtr = {}; - FunctionPtr.Identifier = Identifier->Text; - FunctionPtr.Size = sizeof(void*); - CopyMetaTagsAndClear(TagList, &FunctionPtr.MetaTags); - FunctionPtr.Type = TypeDef_FunctionPointer; - FunctionPtr.Pointer = true; - FunctionPtr.FunctionPtr = {}; - FunctionPtr.FunctionPtr.ReturnTypeIndex = ReturnTypeIndex; - - if (ParseFunctionParameterList(Iter, &FunctionPtr, TagList, TypeTable)) - { - if (TokenAtEquals(Iter, ";")) - { - Result = true; - PushTypeDefOnTypeTable(FunctionPtr, TypeTable); - } - } - } - } - - ApplySnapshotIfNotParsedAndPop(Result, Iter); - if (!Result) - { - *Identifier = {0}; - } - return Result; -} - -internal b32 -ParseTypedef(token_iter* Iter, gs_bucket* TagList, type_table* TypeTable) -{ - b32 Result = false; - PushSnapshot(Iter); - - if (TokenAtEquals(Iter, "typedef")) - { - token TypeToken = {0}; - s32 TypeIndex = -1; - if (TokenAtEquals(Iter, "struct") && - ParseStruct(Iter, &TypeIndex, TagList, TypeTable)) - { - Result = true; - } - else if (ParseFunctionDeclaration(Iter, &TypeToken, TagList, TypeTable)) - { - Result = true; - } - else if (ParseType(Iter, TypeTable, &TypeIndex)) - { - if (TypeIndex < 0) - { - TypeIndex = PushUndeclaredType(Iter->TokenAt->Text, TypeTable); - NextToken(Iter); - } - - b32 IsPointer = ParsePointer(Iter); - - type_definition* BasisType = TypeTable->Types.GetElementAtIndex(TypeIndex); - - type_definition NewType = {}; - NewType.Size = BasisType->Size; - CopyMetaTagsAndClear(TagList, &NewType.MetaTags); - NewType.Type = BasisType->Type; - if (NewType.Type == TypeDef_Struct || - NewType.Type == TypeDef_Union) - { - NewType.Struct = BasisType->Struct; - } - NewType.Pointer = BasisType->Pointer || IsPointer; - - token IdentifierToken = {}; - if (TokenAtEquals(Iter, Token_Identifier, &IdentifierToken)) - { - NewType.Identifier = IdentifierToken.Text; - PushTypeDefOnTypeTable(NewType, TypeTable); - Result = true; - } - } - else - { - string* Error = TakeError(Iter->Errors); - PrintF(Error, "unhandled typedef "); - while (!TokenAtEquals(Iter, ";")) - { - PrintF(Error, "%S ", Iter->TokenAt->Text); - NextToken(Iter); - } - PrintF(Error, "\n"); - } - } - - - ApplySnapshotIfNotParsedAndPop(Result, Iter); - return Result; -} - -internal b32 -ParseEnum (token_iter* Iter, gs_bucket* TagList, type_table* TypeTable) -{ - b32 Result = false; - PushSnapshot(Iter); - - if (TokenAtEquals(Iter, "enum")) - { - token IdentifierToken = {}; - if (TokenAtEquals(Iter, Token_Identifier, &IdentifierToken)) - { - type_definition EnumDecl = {}; - EnumDecl.Identifier = IdentifierToken.Text; - EnumDecl.Size = sizeof(u32); - CopyMetaTagsAndClear(TagList, &EnumDecl.MetaTags); - EnumDecl.Type = TypeDef_Enum; - - if (TokenAtEquals(Iter, "{")) - { - u32 EnumAcc = 0; - - while (!StringsEqual(Iter->TokenAt->Text, MakeStringLiteral("}"))) - { - token EnumIdentifierToken = {}; - if (TokenAtEquals(Iter, Token_Identifier, &EnumIdentifierToken)) - { - if (TokenAtEquals(Iter, "=")) - { - // TODO(Peter): TempValue is just here until we handle all - // const expr that could define an enum value. Its there so - // that if the first token of an expression is a number, - // we can avoid using anything from the expression. - u32 TempValue = EnumAcc; - token NumberToken = {}; - if (TokenAtEquals(Iter, Token_Number, &NumberToken)) - { - parse_result ParsedExpr = ParseSignedInt(StringExpand(NumberToken.Text)); - TempValue = ParsedExpr.SignedIntValue; - } - - // TODO(Peter): Handle setting enums equal to other kinds - // of const exprs. - // We're skipping a whole bunch of stuff now - while (!(StringsEqual(Iter->TokenAt->Text, MakeStringLiteral(",")) || - StringsEqual(Iter->TokenAt->Text, MakeStringLiteral("}")))) - { - TempValue = EnumAcc; - NextToken(Iter); - } - - EnumAcc = TempValue; - } - - s32 EnumValue = EnumAcc++; - if (TokenAtEquals(Iter, ",") || - StringsEqual(Iter->TokenAt->Text, MakeStringLiteral("}"))) - { - EnumDecl.Enum.Identifiers.PushElementOnBucket(EnumIdentifierToken.Text); - EnumDecl.Enum.Values.PushElementOnBucket(EnumValue); - } - else if (!StringsEqual(Iter->TokenAt->Text, MakeStringLiteral("}"))) - { - Result = false; - break; - } - } - } - - if (TokenAtEquals(Iter, "}") && - TokenAtEquals(Iter, ";")) - { - PushTypeDefOnTypeTable(EnumDecl, TypeTable); - Result = true; - } - } - } - } - - ApplySnapshotIfNotParsedAndPop(Result, Iter); - return Result; -} - -internal void -PrintIndent (u32 Indent) -{ - for (u32 i = 0; i < Indent; i++) - { - printf(" "); - } -} - -internal void PrintStructDecl (type_definition* StructDecl, type_table TypeTable, u32 Indent); - -internal void -PrintVariableDecl (variable_decl Member, type_table TypeTable, u32 Indent = 0) -{ - type_definition* MemberTypeDef = TypeTable.Types.GetElementAtIndex(Member.TypeIndex); - if ((MemberTypeDef->Type == TypeDef_Struct || MemberTypeDef->Type == TypeDef_Union) - && MemberTypeDef->Identifier.Length == 0) - { - PrintStructDecl(MemberTypeDef, TypeTable, Indent); - } - else - { - PrintIndent(Indent); - if (Member.TypeIndex == -1) - { - printf("???? "); - } - printf("%.*s ", StringExpand(MemberTypeDef->Identifier)); - } - - if (Member.Pointer) - { - printf("* "); - } - - printf("%.*s", StringExpand(Member.Identifier)); - - if (Member.ArrayCount > 0) - { - printf("[%d]", Member.ArrayCount); - } -} - -internal void -PrintStructDecl (type_definition* StructDecl, type_table TypeTable, u32 Indent = 0) -{ - Assert(StructDecl->Type == TypeDef_Struct || - StructDecl->Type == TypeDef_Union); - - PrintIndent(Indent); - if (StructDecl->Type == TypeDef_Struct) - { - printf("struct "); - } - else if (StructDecl->Type == TypeDef_Union) - { - printf("union "); - } - else { InvalidCodePath; } - - if (StructDecl->Identifier.Length > 0) - { - printf("%.*s ", StringExpand(StructDecl->Identifier)); - } - printf("{\n"); - - for (u32 MemberIndex = 0; MemberIndex < StructDecl->Struct.MemberDecls.Used; MemberIndex++) - { - variable_decl* Member = StructDecl->Struct.MemberDecls.GetElementAtIndex(MemberIndex); - PrintVariableDecl(*Member, TypeTable, Indent + 1); - printf(";\n"); - } - PrintIndent(Indent); - printf("} ( size = %d ) ", StructDecl->Size); -} - -internal void -PrintFunctionPtrDecl (type_definition* FnPtrDecl, type_table TypeTable) -{ - type_definition* ReturnType = TypeTable.Types.GetElementAtIndex(FnPtrDecl->FunctionPtr.ReturnTypeIndex); - printf("%.*s ", StringExpand(ReturnType->Identifier)); - - if (FnPtrDecl->Identifier.Length > 0) - { - printf("%.*s ", StringExpand(FnPtrDecl->Identifier)); - } - printf("("); - - for (u32 MemberIndex = 0; MemberIndex < FnPtrDecl->FunctionPtr.Parameters.Used; MemberIndex++) - { - variable_decl* Param = FnPtrDecl->FunctionPtr.Parameters.GetElementAtIndex(MemberIndex); - PrintVariableDecl(*Param, TypeTable, 0); - printf(", "); - } - - printf(");"); -} - -struct typeinfo_generator -{ - string_builder TypeList; - string_builder StructMembers; - string_builder TypeDefinitions; - - u32 GeneratedInfoTypesCount; - u32 TypesMax; - b8* TypesGeneratedMask; -}; - -internal typeinfo_generator -InitTypeInfoGenerator(type_table TypeTable) -{ - typeinfo_generator Result = {}; - - Result.TypesMax = TypeTable.Types.Used; - Result.TypesGeneratedMask = (b8*)malloc(sizeof(b8) * Result.TypesMax); - GSZeroMemory((u8*)Result.TypesGeneratedMask, Result.TypesMax); - - WriteF(&Result.TypeList, "enum gsm_struct_type\n{\n"); - - WriteF(&Result.TypeDefinitions, "static gsm_struct_type_info StructTypes[] = {\n"); - return Result; -} - -internal void -FinishGeneratingTypes(typeinfo_generator* Generator) -{ - WriteF(&Generator->TypeList, "gsm_StructTypeCount,\n};\n\n"); - - WriteF(&Generator->StructMembers, "\n"); - - WriteF(&Generator->TypeDefinitions, "};\n"); - WriteF(&Generator->TypeDefinitions, "gsm_u32 StructTypesCount = %d;\n", Generator->GeneratedInfoTypesCount); -} - -internal void -GenerateMetaTagInfo (gs_bucket Tags, string_builder* Builder) -{ - WriteF(Builder, "{"); - for (u32 t = 0; t < Tags.Used; t++) - { - meta_tag* Tag = Tags.GetElementAtIndex(t); - WriteF(Builder, "{ \"%S\", %d }", Tag->Identifier, Tag->Identifier.Length); - if ((t + 1) < Tags.Used) - { - WriteF(Builder, ", "); - } - } - WriteF(Builder, "}, %d", Tags.Used); -} - -internal void -GenerateStructMemberInfo (variable_decl* Member, string StructIdentifier, type_table TypeTable, typeinfo_generator* Gen) -{ - WriteF(&Gen->StructMembers, "{ \"%S\", %d, ", Member->Identifier, Member->Identifier.Length); - WriteF(&Gen->StructMembers, "(u64)&((%S*)0)->%S ", StructIdentifier, Member->Identifier); - WriteF(&Gen->StructMembers, "},\n"); -} - -internal void -GenerateTypeInfo (type_definition* Type, u32 TypeIndex, type_table TypeTable, typeinfo_generator* Generator) -{ - Generator->TypesGeneratedMask[TypeIndex] = true; - Generator->GeneratedInfoTypesCount++; - - { - // NOTE(Peter): This block MUST come before generating - // type info for any member types. If it doesn't, it will screw - // up array ordering - - // Lookup Enum - WriteF(&Generator->TypeList, "gsm_StructType_%S,\n", Type->Identifier); - - // Type Info - WriteF(&Generator->TypeDefinitions, "{ gsm_StructType_%S, \"%S\", %d, %d, 0, 0, ", - Type->Identifier, - Type->Identifier, Type->Identifier.Length, - Type->Size - // TODO(Peter): include Meta Tags somehow - ); - if ((Type->Type == TypeDef_Struct || Type->Type == TypeDef_Union) && - Type->Struct.MemberDecls.Used > 0) - { - WriteF(&Generator->TypeDefinitions, "StructMembers_%S, %d },\n", - Type->Identifier, - Type->Struct.MemberDecls.Used); - } - else - { - WriteF(&Generator->TypeDefinitions, "0, 0 },\n"); - } - } - - if (Type->Type == TypeDef_Struct || - Type->Type == TypeDef_Union) - { - for (u32 m = 0; m < Type->Struct.MemberDecls.Used; m++) - { - variable_decl* Member = Type->Struct.MemberDecls.GetElementAtIndex(m); - type_definition* MemberType = TypeTable.Types.GetElementAtIndex(Member->TypeIndex); - - if (MemberType->Identifier.Length == 0) { continue; } // Don't gen info for anonymous struct and union members - if (Generator->TypesGeneratedMask[Member->TypeIndex]) { continue; } - - GenerateTypeInfo(MemberType, Member->TypeIndex, TypeTable, Generator); - } - - // - WriteF(&Generator->StructMembers, "static gsm_struct_member_type_info StructMembers_%S[] = {\n", Type->Identifier); - for (u32 m = 0; m < Type->Struct.MemberDecls.Used; m++) - { - variable_decl* Member = Type->Struct.MemberDecls.GetElementAtIndex(m); - type_definition* MemberType = TypeTable.Types.GetElementAtIndex(Member->TypeIndex); - - if (MemberType->Identifier.Length > 0) - { - GenerateStructMemberInfo(Member, Type->Identifier, TypeTable, Generator); - } - else if (MemberType->Type == TypeDef_Struct || - MemberType->Type == TypeDef_Union) - { - // Anonymous Members - for (u32 a = 0; a < MemberType->Struct.MemberDecls.Used; a++) - { - variable_decl* AnonMember = MemberType->Struct.MemberDecls.GetElementAtIndex(a); - GenerateStructMemberInfo(AnonMember, Type->Identifier, TypeTable, Generator); - } - } - } - WriteF(&Generator->StructMembers, "};\n", Type->Struct.MemberDecls.Used); - } -} - -internal void -GenerateFilteredTypeInfo (string MetaTagFilter, type_table TypeTable, typeinfo_generator* Generator) -{ - for (u32 i = 0; i < TypeTable.Types.Used; i++) - { - if (Generator->TypesGeneratedMask[i]) - { - continue; - } - - type_definition* Type = TypeTable.Types.GetElementAtIndex(i); - if (HasTag(MetaTagFilter, Type->MetaTags)) - { - GenerateTypeInfo(Type, i, TypeTable, Generator); - } - } -} - -struct gs_meta_preprocessor -{ - errors Errors; - - gs_bucket SourceFiles; - gs_bucket Tokens; - - gs_bucket TagList; - - type_table TypeTable; - - // Performance - s64 PreprocessorStartTime; - s64 PreprocessorEndTime; -}; - -internal gs_meta_preprocessor -PreprocessProgram (char* SourceFile) -{ - gs_meta_preprocessor Meta = {}; - - Meta.PreprocessorStartTime = GetWallClock(); - - PopulateTableWithDefaultCPPTypes(&Meta.TypeTable); - - string CurrentWorkingDirectory = MakeString((char*)malloc(1024), 0, 1024); - - string RootFile = MakeString(SourceFile); - AddFileToSource(RootFile, &Meta.SourceFiles, &Meta.Errors); - - s32 LastSlash = ReverseSearchForCharInSet(RootFile, "\\/"); - if (LastSlash <= 0) - { - PushFError(&Meta.Errors, "%S: File path invalid.", RootFile); - return Meta; - } - - string RootPath = Substring(RootFile, 0, LastSlash + 1); - CopyStringTo(RootPath, &CurrentWorkingDirectory); - - for (u32 SourceFileIdx = 0; SourceFileIdx < Meta.SourceFiles.Used; SourceFileIdx++) - { - source_code_file* File = Meta.SourceFiles.GetElementAtIndex(SourceFileIdx); - TokenizeFile(File, &Meta.Tokens); - - token_iter Iter = {}; - Iter.Tokens = &Meta.Tokens; - Iter.FirstToken = File->FirstTokenIndex; - Iter.LastToken = File->LastTokenIndex; - Iter.TokenAtIndex = Iter.FirstToken; - Iter.TokenAt = Meta.Tokens.GetElementAtIndex(Iter.TokenAtIndex); - Iter.Errors = &Meta.Errors; - - while (Iter.TokenAtIndex < Iter.LastToken) - { - b32 ParseSuccess = false; - - s32 TypeIndex = -1; - if (TokenAtEquals(&Iter, "#include")) - { - token* IncludeFile = Iter.TokenAt; - - // NOTE(Peter): For now we aren't going in and preprocessing the header files - // we include from the system - // Token_Operator is used to check if the include is of the form '#include ' - // and skip it. - // TODO(Peter): This is only a rough approximation of ignoring system headers - // TODO(Peter): We should actually see what parsing system headers would entail - if (IncludeFile->Type != Token_Operator) - { - string TempFilePath = IncludeFile->Text; - - // NOTE(Peter): if the path is NOT absolute ie "C:\etc - if (!(IsAlpha(TempFilePath.Memory[0]) && - TempFilePath.Memory[1] == ':' && - TempFilePath.Memory[2] == '\\')) - { - TempFilePath = CurrentWorkingDirectory; - ConcatString(IncludeFile->Text, &TempFilePath); - NullTerminate(&TempFilePath); - } - - ParseSuccess = true; - if (!FileAlreadyInSource(TempFilePath, Meta.SourceFiles)) - { - AddFileToSource(TempFilePath, &Meta.SourceFiles, &Meta.Errors); - } - } - } - else if(ParseMetaTag(&Iter, &Meta.TagList)) - { - ParseSuccess = true; - } - else if (ParseEnum(&Iter, &Meta.TagList, &Meta.TypeTable)) - { - ParseSuccess = true; - } - else if (ParseStruct(&Iter, &TypeIndex, &Meta.TagList, &Meta.TypeTable)) - { - ParseSuccess = true; - } - else if (ParseTypedef(&Iter, &Meta.TagList, &Meta.TypeTable)) - { - ParseSuccess = true; - } - - if (!ParseSuccess) - { - NextToken(&Iter); - } - } - } - - // Type Table Fixup - for (u32 i = 0; i < Meta.TypeTable.Types.Used; i++) - { - type_definition* TypeDef = Meta.TypeTable.Types.GetElementAtIndex(i); - if (TypeDef->Type == TypeDef_Struct) - { - FixUpStructSize(i, Meta.TypeTable, &Meta.Errors); - } - else if (TypeDef->Type == TypeDef_Union) - { - FixUpUnionSize(i, Meta.TypeTable, &Meta.Errors); - } - } - - Meta.PreprocessorEndTime = GetWallClock(); - return Meta; -} - -internal void -FinishMetaprogram(gs_meta_preprocessor* Meta) -{ - PrintAllErrors(Meta->Errors); - - s64 TotalEnd = GetWallClock(); - r32 PreprocTime = GetSecondsElapsed(Meta->PreprocessorStartTime, Meta->PreprocessorEndTime); - r32 TotalTime = GetSecondsElapsed(Meta->PreprocessorStartTime, TotalEnd); - r32 UserTime = TotalTime - PreprocTime; - printf("Metaprogram Performance:\n"); - printf(" Preproc Time: %.*f sec\n", 6, PreprocTime); - printf(" Custom Time: %.*f sec\n", 6, UserTime); - printf(" Total Time: %.*f sec\n", 6, TotalTime); - -} +#include "gs_meta.cpp" +#include "gs_meta_typeinfo_generator.h" int main(int ArgCount, char* Args[]) { diff --git a/meta/gs_meta.cpp b/meta/gs_meta.cpp index 9ba0add..24d034c 100644 --- a/meta/gs_meta.cpp +++ b/meta/gs_meta.cpp @@ -1,492 +1,247 @@ -#include "..\src\gs_language.h" -#include "..\src\gs_string.h" +#include +#include + +#include +#include +#include "..\src\gs_platform.h" +#include +#include -#include "gs_meta_error.h" #include "gs_meta_lexer.h" +#include "gs_meta_error.h" -#ifndef MAX_PATH -#define MAX_PATH 512 -#endif // MAX_PATH +#include "foldhaus_meta_type_table.h" -#define META_FILES_ARRAY_INCREMENT_SIZE 32 - -struct file_contents +struct source_code_file { - u8* Backbuffer; - string Buffer; -}; - -#define TOKEN_BUFFER_SIZE 256 - -struct token_buffer -{ - token* Tokens; - s32 Used; - s32 Max; - token_buffer* Next; -}; - -struct token_list -{ - token_buffer* Head; - s32 TotalUsed; - s32 TotalMax; -}; - -struct token_list_iterator -{ - token_list* List; - token_buffer* BufferAt; - token* At; - s32 AtTotalIndex; -}; - -enum basic_type -{ - BasicType_Int8, - BasicType_Int16, - BasicType_Int32, - BasicType_Int64, - BasicType_UnsignedInt8, - BasicType_UnsignedInt16, - BasicType_UnsignedInt32, - BasicType_UnsignedInt64, - BasicType_Char, - BasicType_Float32, - BasicType_Float64, - BasicType_Void, -}; - -struct variable_definition_symbol -{ - string Identifier; - basic_type Type; - b32 IsArray; - s32 Size; -}; - -struct struct_definition_symbol -{ - string Identifier; - s32 MemberCount; - variable_definition_symbol* Members; -}; - -struct function_definition_symbol -{ - string Identifier; + string Path; + s32 FileSize; + string Contents; - s32 ArgumentCount; - variable_definition_symbol* Arguments; + s32 FirstTokenIndex; + s32 LastTokenIndex; +}; + +struct token_iter +{ + gs_bucket* Tokens; + token* TokenAt; + s32 TokenAtIndex; + s32 FirstToken; + s32 LastToken; - // TODO(Peter): An AST of the actual code that makes up the function? +#define TOKEN_ITER_SNAPSHOTS_MAX 64 + u32 SnapshotsUsed; + u32 Snapshots[TOKEN_ITER_SNAPSHOTS_MAX]; + + errors* Errors; }; -enum symbol_type +struct gs_meta_preprocessor { - SymbolType_Function, - SymbolType_Struct + errors Errors; + + gs_bucket SourceFiles; + gs_bucket Tokens; + + gs_bucket TagList; + + type_table TypeTable; + + // Performance + s64 PreprocessorStartTime; + s64 PreprocessorEndTime; }; -struct symbol +// ------------------------ +// Timing / Performance +// ------------------------ + +internal s64 +GetWallClock () { - symbol_type Type; - union + LARGE_INTEGER Time; + if (!QueryPerformanceCounter(&Time)) { - struct_definition_symbol StructDef; - function_definition_symbol FunctionDef; - }; -}; - -enum parser_symbol_type -{ - ParserSymbol_Invalid, - ParserSymbol_Unknown, - - ParserSymbol_Auto, - ParserSymbol_Break, - ParserSymbol_Case, - ParserSymbol_Char, - ParserSymbol_Const, - ParserSymbol_Continue, - ParserSymbol_Default, - ParserSymbol_Do, - ParserSymbol_Double, - ParserSymbol_Else, - ParserSymbol_Enum, - ParserSymbol_Extern, - ParserSymbol_Float, - ParserSymbol_For, - ParserSymbol_Goto, - ParserSymbol_If, - ParserSymbol_Inline, - ParserSymbol_Int, - ParserSymbol_Long, - ParserSymbol_Register, - ParserSymbol_Restrict, - ParserSymbol_Return, - ParserSymbol_Short, - ParserSymbol_Signed, - ParserSymbol_Sizeof, - ParserSymbol_Static, - ParserSymbol_Struct, - ParserSymbol_Switch, - ParserSymbol_Typedef, - ParserSymbol_Union, - ParserSymbol_Unsigned, - ParserSymbol_Void, - ParserSymbol_Volatile, - ParserSymbol_While, - - // Assignment Operators - ParserSymbol_AssignEquals, - ParserSymbol_PlusEquals, - ParserSymbol_MinusEquals, - ParserSymbol_TimesEquals, - ParserSymbol_DividedEquals, - ParserSymbol_ModEquals, - ParserSymbol_BitAndEquals, - ParserSymbol_BitOrEquals, - ParserSymbol_BitNotEquals, - ParserSymbol_BitShiftUpEquals, - ParserSymbol_BitShiftDownEquals, - - // Increment/Decrement Operators - ParserSymbol_Increment, - ParserSymbol_Decrement, -}; - -struct parser_symbol_definition -{ - parser_symbol_type Type; - string Text; -}; - -global_variable parser_symbol_definition ParserSymbolTable[] = -{ - // Keywords - { ParserSymbol_Auto, MakeStringLiteral("auto")}, - { ParserSymbol_Break, MakeStringLiteral("break")}, - { ParserSymbol_Case, MakeStringLiteral("case")}, - { ParserSymbol_Char, MakeStringLiteral("char")}, - { ParserSymbol_Const, MakeStringLiteral("const")}, - { ParserSymbol_Continue, MakeStringLiteral("continue")}, - { ParserSymbol_Default, MakeStringLiteral("default")}, - { ParserSymbol_Do, MakeStringLiteral("do")}, - { ParserSymbol_Double, MakeStringLiteral("double")}, - { ParserSymbol_Else, MakeStringLiteral("else")}, - { ParserSymbol_Enum, MakeStringLiteral("enum")}, - { ParserSymbol_Extern, MakeStringLiteral("extern")}, - { ParserSymbol_Float, MakeStringLiteral("float")}, - { ParserSymbol_For, MakeStringLiteral("for")}, - { ParserSymbol_Goto, MakeStringLiteral("goto")}, - { ParserSymbol_If, MakeStringLiteral("if")}, - { ParserSymbol_Inline, MakeStringLiteral("inline")}, - { ParserSymbol_Int, MakeStringLiteral("int")}, - { ParserSymbol_Long, MakeStringLiteral("long")}, - { ParserSymbol_Register, MakeStringLiteral("register")}, - { ParserSymbol_Restrict, MakeStringLiteral("restrict")}, - { ParserSymbol_Return, MakeStringLiteral("return")}, - { ParserSymbol_Short, MakeStringLiteral("short")}, - { ParserSymbol_Signed, MakeStringLiteral("signed")}, - { ParserSymbol_Sizeof, MakeStringLiteral("sizeof")}, - { ParserSymbol_Static, MakeStringLiteral("static")}, - { ParserSymbol_Struct, MakeStringLiteral("struct")}, - { ParserSymbol_Switch, MakeStringLiteral("switch")}, - { ParserSymbol_Typedef, MakeStringLiteral("typedef")}, - { ParserSymbol_Union, MakeStringLiteral("union")}, - { ParserSymbol_Unsigned, MakeStringLiteral("unsigned")}, - { ParserSymbol_Void, MakeStringLiteral("void")}, - { ParserSymbol_Volatile, MakeStringLiteral("volatile")}, - { ParserSymbol_While, MakeStringLiteral("while")}, - - // Assignment Operators - { ParserSymbol_AssignEquals, MakeStringLiteral("=")}, - { ParserSymbol_PlusEquals, MakeStringLiteral("+=")}, - { ParserSymbol_MinusEquals, MakeStringLiteral("-=")}, - { ParserSymbol_TimesEquals, MakeStringLiteral("*=")}, - { ParserSymbol_DividedEquals, MakeStringLiteral("/=")}, - { ParserSymbol_ModEquals, MakeStringLiteral("%=")}, - { ParserSymbol_BitAndEquals, MakeStringLiteral("&=")}, - { ParserSymbol_BitOrEquals, MakeStringLiteral("|=")}, - { ParserSymbol_BitNotEquals, MakeStringLiteral("^=")}, - { ParserSymbol_BitShiftUpEquals, MakeStringLiteral("<<=")}, - { ParserSymbol_BitShiftDownEquals, MakeStringLiteral(">>=")}, - - // Increment/Decrement Operators - { ParserSymbol_Increment, MakeStringLiteral("++")}, - { ParserSymbol_Decrement, MakeStringLiteral("--")}, - - /* - // Arithmetic Operators - { ParserSymbol_, MakeStringLiteral("")}, - { ParserSymbol_, MakeStringLiteral("")}, - { ParserSymbol_, MakeStringLiteral("")}, - { ParserSymbol_, MakeStringLiteral("")}, - { ParserSymbol_, MakeStringLiteral("")}, - { ParserSymbol_, MakeStringLiteral("")}, - { ParserSymbol_, MakeStringLiteral("")}, - { ParserSymbol_, MakeStringLiteral("")}, - { ParserSymbol_, MakeStringLiteral("")}, - { ParserSymbol_, MakeStringLiteral("")}, - { ParserSymbol_, MakeStringLiteral("")}, - */ -}; - -struct gs_meta_processor -{ - error_list ErrorList; - - u8* FileStringMemory; - s32 FileStringMemorySize; - - string* Files; - file_contents* Contents; - token_list* FileTokens; - s32 FilesUsed; - s32 FilesMax; -}; - -internal gs_meta_processor -CreateMetaProcessor () -{ - gs_meta_processor Result = {}; - return Result; + s32 Error = GetLastError(); + InvalidCodePath; + } + return (s64)Time.QuadPart; } -internal void -SetMetaFilesStringMemory (gs_meta_processor* Meta, s32 StartIndex, s32 EndIndex) +internal s64 +GetPerformanceFrequency () { - char* StringMemoryAt = (char*)(Meta->FileStringMemory + (MAX_PATH * StartIndex)); - for (s32 i = StartIndex; i < EndIndex; i++) + LARGE_INTEGER Frequency; + if (!QueryPerformanceFrequency(&Frequency)) { - string* String = Meta->Files + i; - InitializeString(String, StringMemoryAt, MAX_PATH); - StringMemoryAt += MAX_PATH; + s32 Error = GetLastError(); + InvalidCodePath; } + return (s64)Frequency.QuadPart; +} + +internal r32 +GetSecondsElapsed(s64 StartCycles, s64 EndCycles) +{ + s64 Frequency = GetPerformanceFrequency(); + r32 SecondsElapsed = (r32)(EndCycles - StartCycles) / (r32)(Frequency); + return SecondsElapsed; +} + +// ------------------------ +// Token Iterator +// ------------------------ + +internal token* +NextToken (token_iter* Iter) +{ + if (Iter->TokenAtIndex < Iter->LastToken) + { + Iter->TokenAtIndex++; + Iter->TokenAt = Iter->Tokens->GetElementAtIndex(Iter->TokenAtIndex); + } + + return Iter->TokenAt; } internal b32 -IsValidFileType(char* Filename) +TokenAtEquals(token_iter* Iter, char* String) { - string FileString = MakeString(Filename); - s32 IndexOfDot = LastIndexOfChar(FileString, '.'); - string ExtensionString = Substring(FileString, IndexOfDot); - b32 Result = false; - if (StringsEqual(ExtensionString, MakeStringLiteral("cpp")) || - StringsEqual(ExtensionString, MakeStringLiteral("h"))) + if (StringEqualsCharArray(Iter->TokenAt->Text, String)) { Result = true; + NextToken(Iter); + } + return Result; +} + +internal b32 +TokenAtEquals(token_iter* Iter, token_type Type) +{ + b32 Result = false; + if (Iter->TokenAt->Type == Type) + { + Result = true; + NextToken(Iter); + } + return Result; +} + +internal b32 +TokenAtEquals(token_iter* Iter, token_type Type, token* Token) +{ + b32 Result = false; + if (Iter->TokenAt->Type == Type) + { + Result = true; + *Token = *Iter->TokenAt; + NextToken(Iter); } - return Result; } internal void -AddFile(gs_meta_processor* Meta, char* Filename) +PushSnapshot (token_iter* Iter) { - if (!IsValidFileType(Filename)) - { - LogError(&Meta->ErrorList, "AddFile: %s has an extension that cannot be processed.", Filename); - } - - if(!Meta->Files) - { - Meta->FilesMax = META_FILES_ARRAY_INCREMENT_SIZE; - Meta->FilesUsed = 0; - Meta->Files = (string*)malloc(sizeof(string) * Meta->FilesMax); - - Meta->FileStringMemorySize = Meta->FilesMax * MAX_PATH; - Meta->FileStringMemory = (u8*)malloc(Meta->FileStringMemorySize); - - SetMetaFilesStringMemory(Meta, 0, Meta->FilesMax); - } - - if (Meta->Files && Meta->FilesUsed >= Meta->FilesMax) - { - Meta->FilesMax += META_FILES_ARRAY_INCREMENT_SIZE; - Meta->Files = (string*)realloc(Meta->Files, sizeof(string) * Meta->FilesMax); - - Meta->FileStringMemorySize = Meta->FilesMax * MAX_PATH; - Meta->FileStringMemory = (u8*)realloc(Meta->FileStringMemory, Meta->FileStringMemorySize); - - SetMetaFilesStringMemory(Meta, Meta->FilesUsed, Meta->FilesMax); - } - - string* File = Meta->Files + Meta->FilesUsed++; - File->Length = CharArrayLength(Filename); - GSMemCopy(Filename, File->Memory, File->Length); - NullTerminate(File); + Iter->Snapshots[Iter->SnapshotsUsed++] = Iter->TokenAtIndex; } internal void -LoadFileContents (file_contents* Contents, string* FileName, error_list* Errors) +PopSnapshot (token_iter* Iter) { - FILE* ReadFile = fopen(FileName->Memory, "r"); + if (Iter->SnapshotsUsed > 0) + { + Iter->SnapshotsUsed -= 1; + } +} + +internal void +ApplySnapshot (token_iter* Iter) +{ + u32 SnapshotIndex = Iter->SnapshotsUsed; + u32 SnapshotPoint = Iter->Snapshots[SnapshotIndex]; + Iter->TokenAtIndex = SnapshotPoint; + Iter->TokenAt = Iter->Tokens->GetElementAtIndex(SnapshotPoint); +} + +internal void +ApplySnapshotIfNotParsedAndPop(b32 ParseSuccess, token_iter* Iter) +{ + PopSnapshot(Iter); + if (!ParseSuccess) + { + ApplySnapshot(Iter); + } +} + + +internal s32 +GetFileSize (char* FileName) +{ + s32 Result = 0; + + FILE* ReadFile = fopen(FileName, "r"); if (ReadFile) { fseek(ReadFile, 0, SEEK_END); size_t FileSize = ftell(ReadFile); fseek(ReadFile, 0, SEEK_SET); - if (FileSize > 0) - { - Contents->Backbuffer = (u8*)malloc(FileSize + 1); - size_t ReadSize = fread(Contents->Backbuffer, 1, FileSize, ReadFile); - Contents->Backbuffer[FileSize] = 0; - - InitializeString(&Contents->Buffer, (char*)Contents->Backbuffer, (s32)FileSize + 1); - Contents->Buffer.Length = (s32)FileSize + 1; - } - else - { - LogError(Errors, "LoadFileContents: File Size Was Zero for %s", FileName->Memory); - } + + Result = (s32)FileSize; + fclose(ReadFile); + } + + return Result; +} + +// ------------------------- +// Source File Handling +// ------------------------- + +internal s32 +ReadEntireFileAndNullTerminate (source_code_file* File, errors* Errors) +{ + s32 LengthRead = 0; + + FILE* ReadFile = fopen(File->Path.Memory, "r"); + if (ReadFile) + { + fseek(ReadFile, 0, SEEK_END); + size_t FileSize = ftell(ReadFile); + fseek(ReadFile, 0, SEEK_SET); + + Assert(File->Contents.Memory == 0); + File->Contents.Max = (s32)FileSize + 1; + File->Contents.Memory = (char*)malloc(File->Contents.Max); + + size_t ReadSize = fread(File->Contents.Memory, 1, FileSize, ReadFile); + File->Contents.Memory[FileSize] = 0; + File->Contents.Length = (s32)ReadSize; + + LengthRead = (s32)ReadSize + 1; fclose(ReadFile); } else { - LogError(Errors, "LoadFileContents: Could Not Read File %s", FileName->Memory); + PushFError(Errors, "Could Not Read File: %S", File->Path); } -} - -internal void -LoadAllFiles (gs_meta_processor* Meta) -{ - Meta->Contents = (file_contents*)malloc(sizeof(file_contents) * Meta->FilesUsed); - - for (s32 FileIdx = 0; FileIdx < Meta->FilesUsed; FileIdx++) - { - file_contents* Contents = Meta->Contents + FileIdx; - string* FileName = Meta->Files + FileIdx; - LoadFileContents(Contents, FileName, &Meta->ErrorList); - } -} - -internal token* -PushTokenOnList(token_list* List) -{ - token* Result = 0; - - if (!List->Head) - { - s32 NewBufferSize = sizeof(token_buffer) + (sizeof(token) * TOKEN_BUFFER_SIZE); - u8* NewBufferContents = (u8*)malloc(NewBufferSize); - List->Head = (token_buffer*)NewBufferContents; - List->Head->Used = 0; - List->Head->Max = TOKEN_BUFFER_SIZE; - List->Head->Tokens = (token*)(NewBufferContents + sizeof(token_buffer)); - List->TotalUsed = List->Head->Used; - List->TotalMax = List->Head->Max; - } - else if (List->TotalUsed >= List->TotalMax) - { - s32 NewBufferSize = sizeof(token_buffer) + (sizeof(token) * TOKEN_BUFFER_SIZE); - u8* NewBufferContents = (u8*)malloc(NewBufferSize); - - token_buffer* NewBuffer = (token_buffer*)NewBufferContents; - NewBuffer->Tokens = (token*)(NewBufferContents + sizeof(token_buffer)); - - NewBuffer->Next = NewBuffer; - List->Head = NewBuffer; - List->TotalUsed += List->Head->Used; - List->TotalMax += List->Head->Max; - } - - Result = List->Head->Tokens + List->Head->Used++; - List->TotalUsed++; - - return Result; -} - -internal void -LexFile (file_contents* Contents, token_list* TokensList) -{ - tokenizer FileTokenizer = {}; - FileTokenizer.Memory = Contents->Buffer.Memory; - FileTokenizer.MemoryLength = Contents->Buffer.Length; - FileTokenizer.At = FileTokenizer.Memory; - - while (AtValidPosition(FileTokenizer)) - { - token* Token = PushTokenOnList(TokensList); - *Token = GetNextToken(&FileTokenizer); - } -} - -internal void -LexAllFiles (gs_meta_processor* Meta) -{ - LoadAllFiles(Meta); - - Meta->FileTokens = (token_list*)malloc(sizeof(token_list) * Meta->FilesUsed); - - for (s32 SourceFile = 0; SourceFile < Meta->FilesUsed; SourceFile++) - { - Meta->FileTokens[SourceFile] = {}; - - token_list* FileTokenList = Meta->FileTokens + SourceFile; - file_contents* FileContents = Meta->Contents + SourceFile; - LexFile (FileContents, FileTokenList); - } -} - -internal token_list_iterator -GetTokenIterator(token_list* List) -{ - token_list_iterator Result = {}; - Result.List = List; - Result.BufferAt = List->Head; - Result.At = List->Head->Tokens; - Result.AtTotalIndex = 0; - return Result; + return LengthRead; } internal b32 -IsValid (token_list_iterator Iterator) +FileAlreadyInSource(string Path, gs_bucket SourceFiles) { b32 Result = false; - if (Iterator.At && Iterator.AtTotalIndex < Iterator.List->TotalUsed) - { - Result = true; - } - return Result; -} - -internal void -Advance (token_list_iterator* Iterator) -{ - if ((Iterator->At - Iterator->BufferAt->Tokens) >= Iterator->BufferAt->Used) - { - Iterator->BufferAt = Iterator->BufferAt->Next; - if (Iterator->BufferAt) - { - Iterator->At = Iterator->BufferAt->Tokens; - Iterator->AtTotalIndex++; - } - else - { - Iterator->At = 0; - } - } - else - { - Iterator->At++; - Iterator->AtTotalIndex++; - } -} - -internal parser_symbol_type -GetSymbolType (string Text, parser_symbol_type Fallback) -{ - parser_symbol_type Result = Fallback; - for (s32 i = 0; i < (sizeof(ParserSymbolTable)/sizeof(ParserSymbolTable[0])); i++) + for (u32 i = 0; i < SourceFiles.Used; i++) { - if (StringsEqual(Text, ParserSymbolTable[i].Text)) + source_code_file* File = SourceFiles.GetElementAtIndex(i); + if (StringsEqual(File->Path, Path)) { - Result = ParserSymbolTable[i].Type; + Result = true; break; } } @@ -495,253 +250,976 @@ GetSymbolType (string Text, parser_symbol_type Fallback) } internal void -ParseFile (token_list* TokenList, gs_meta_processor* Meta) +AddFileToSource(string RelativePath, gs_bucket* SourceFiles, errors* Errors) { - for (token_list_iterator TokenIter = GetTokenIterator(TokenList); - IsValid(TokenIter); - Advance(&TokenIter)) + source_code_file File = {0}; + + File.FirstTokenIndex = -1; + File.LastTokenIndex = -1; + + u32 PathLength = RelativePath.Length + 1; + File.Path = MakeString((char*)malloc(sizeof(char) * PathLength), 0, PathLength); + CopyStringTo(RelativePath, &File.Path); + NullTerminate(&File.Path); + + File.FileSize = ReadEntireFileAndNullTerminate(&File, Errors); + + if (File.FileSize > 0) { - token* At = TokenIter.At; - parser_symbol_type SymbolType = GetSymbolType(At->Text, ParserSymbol_Unknown); - - switch (SymbolType) - { - case SymbolType_Struct: - { - printf("Found Struct: %.*s\n", (At + 1)->Text.Length, (At + 1)->Text.Memory); - }break; - } + SourceFiles->PushElementOnBucket(File); + } + else + { + PushFError(Errors, "Error: Could not load file %S\n", RelativePath); } } internal void -ParseAllFiles (gs_meta_processor* Meta) +TokenizeFile (source_code_file* File, gs_bucket* Tokens) { - for (s32 SourceFile = 0; SourceFile < Meta->FilesUsed; SourceFile++) + tokenizer Tokenizer = {}; + Tokenizer.At = File->Contents.Memory; + Tokenizer.Memory = File->Contents.Memory; + Tokenizer.MemoryLength = File->Contents.Max; + + token* LastToken = 0; + while(AtValidPosition(Tokenizer)) { - token_list* FileTokenList = Meta->FileTokens + SourceFile; - ParseFile(FileTokenList, Meta); + token NewToken = GetNextToken(&Tokenizer); + u32 TokenIndex = Tokens->PushElementOnBucket(NewToken); + if (File->FirstTokenIndex < 0) + { + File->FirstTokenIndex = (s32)TokenIndex; + } } + + File->LastTokenIndex = Tokens->Used - 1; } -#if 0 -#include -#define GS_PRINTF(v) OutputDebugStringA(v) -#include "gs_string.h" +// ------------------------ +// Parsing +// ------------------------ -static char DEBUGCharArray[256]; -#define GS_DEBUG_PRINTF(format, ...) sprintf(DEBUGCharArray, format, __VA_ARGS__); OutputDebugStringA(DEBUGCharArray); - -#include "gs_meta_lexer.h" -#include "gs_meta_parser.h" -#include "gs_meta_generator.h" - -internal char* -ReadEntireFileAndNullTerminate (char* Filename) +internal b32 +ParseMetaTag(token_iter* Iter, gs_bucket* TagList) { - char* Result = 0; + b32 Result = false; + PushSnapshot(Iter); - FILE* ReadFile = fopen(Filename, "r"); - if (ReadFile) + if (TokenAtEquals(Iter, "GSMetaTag") && + TokenAtEquals(Iter, "(")) { - fseek(ReadFile, 0, SEEK_END); - size_t FileSize = ftell(ReadFile); - fseek(ReadFile, 0, SEEK_SET); - - Result = (char*)malloc(FileSize + 1); - size_t ReadSize = fread(Result, 1, FileSize, ReadFile); - Result[FileSize] = 0; - - fclose(ReadFile); + token MetaIdentifier = {0}; + if (TokenAtEquals(Iter, Token_Identifier, &MetaIdentifier)) + { + TagList->PushElementOnBucket(MetaIdentifier); + if (StringsEqual(MetaIdentifier.Text, MakeStringLiteral("breakpoint"))) + { + // NOTE(Peter): This is not a temporary breakpoint. It is + // used to be able to break the meta program at specific points + // throughout execution + __debugbreak(); + } + + if (TokenAtEquals(Iter, ")") && + TokenAtEquals(Iter, ";")) + { + Result = true; + } + } } - else + + ApplySnapshotIfNotParsedAndPop(Result, Iter); + return Result; +} + +internal b32 +ParseSignedness (token_iter* Iter) +{ + // NOTE(Peter): This doesn't really do much at the moment, but + // I want all signedness parsing to happen in one place in case + // we ever need to do anything with it. + + b32 Result = false; + + if (TokenAtEquals(Iter, "unsigned") || + TokenAtEquals(Iter, "signed")) { - GS_DEBUG_PRINTF("Failed to fopen file"); + Result = true; } return Result; } -int PrecompileFile (char* FileName) +internal b32 +ShortInt (token_iter* Iter, s32* TypeIndexOut, type_table TypeTable) { - char* SourceFileContents = ReadEntireFileAndNullTerminate(FileName); - if (!SourceFileContents) + b32 Result = false; + PushSnapshot(Iter); + + ParseSignedness(Iter); + if (TokenAtEquals(Iter, "short")) { - GS_DEBUG_PRINTF("Failed to get source file contents"); - return 0; - } - - tokenizer Tokenizer = {}; - Tokenizer.At = SourceFileContents; - - s32 TokensGrowSize = 256; - s32 TokensMax = TokensGrowSize; - s32 TokensCount = 0; - token* Tokens = (token*)malloc(TokensGrowSize * sizeof(token)); - - token* Current = Tokens; - while (Tokenizer.At[0]) - { - *Current = GetNextToken(&Tokenizer); - Current->Next = 0; - - TokensCount++; - - if (TokensCount >= TokensMax) + Result = true; + if (TokenAtEquals(Iter, "int")) { - token* Addition = (token*)malloc(TokensGrowSize * sizeof(token)); - TokensMax += TokensGrowSize; - - token* Old = Current; - Current = Addition; - Old->Next = Current; - } - else if(Tokenizer.At[0]) - { - token* Old = Current; - Current++; - Old->Next = Current; + Result = true; } } - - - Current = Tokens; -#if 0 // Print Tokens - if (Current) - { - do - { - GS_DEBUG_PRINTF("%s %.*s\n", TokenNames[(int)Current->Type], Current->TextLength, Current->Text); - Current = Current->Next; - }while(Current); + ApplySnapshotIfNotParsedAndPop(Result, Iter); + if (Result) + { + *TypeIndexOut = GetIndexOfType(MakeStringLiteral("short int"), TypeTable); } -#endif + return Result; +} + +internal b32 +Int (token_iter* Iter, s32* TypeIndexOut, type_table TypeTable) +{ + b32 Result = false; + PushSnapshot(Iter); - ast_node Ast = {}; - Ast.Type = ASTNode_Program; - ast_node* CurrentNode = Ast.Children; - - // Preprocessor Defines - // TODO(Peter): Actually preprocess the file - token* CurrentToken = Tokens; - /*while (CurrentToken) + ParseSignedness(Iter); + if (TokenAtEquals(Iter, "int")) { - CurrentToken = CurrentToken->Next; + Result = true; } - */ - // Analyze File - CurrentToken = Tokens; - while (CurrentToken) + ApplySnapshotIfNotParsedAndPop(Result, Iter); + if (Result) + { + *TypeIndexOut = GetIndexOfType(MakeStringLiteral("int"), TypeTable); + } + return Result; +} + +internal b32 +LongInt (token_iter* Iter, s32* TypeIndexOut, type_table TypeTable) +{ + b32 Result = false; + PushSnapshot(Iter); + + ParseSignedness(Iter); + if (TokenAtEquals(Iter, "long")) { - /*GS_DEBUG_PRINTF("%s %.*s\n", TokenNames[(int)CurrentToken->Type], - CurrentToken->TextLength, CurrentToken->Text); - */ - - parse_result ParseResult = {}; - ParseResult.Parsed = false; - - if (CurrentToken->Type == Token_Identifier) + Result = true; + if (TokenAtEquals(Iter, "int")) { - if (StringsEqual(CurrentToken->Text, "struct", 6)) + Result = true; + } + } + + ApplySnapshotIfNotParsedAndPop(Result, Iter); + if (Result) + { + *TypeIndexOut = GetIndexOfType(MakeStringLiteral("long int"), TypeTable); + } + return Result; +} + +internal b32 +LongLongInt (token_iter* Iter, s32* TypeIndexOut, type_table TypeTable) +{ + b32 Result = false; + PushSnapshot(Iter); + + ParseSignedness(Iter); + if (TokenAtEquals(Iter, "long")) + { + if (TokenAtEquals(Iter, "long")) + { + Result = true; + if (TokenAtEquals(Iter, "int")) { - ParseResult = ParseStructDeclaration(CurrentNode, CurrentToken); - CurrentToken = ParseResult.NextToken; + Result = true; } - else if (IsFunction(CurrentToken)) + } + } + + ApplySnapshotIfNotParsedAndPop(Result, Iter); + if (Result) + { + *TypeIndexOut = GetIndexOfType(MakeStringLiteral("long long int"), TypeTable); + } + return Result; +} + +internal b32 +ParseChar(token_iter* Iter, s32* TypeIndexOut, type_table TypeTable) +{ + b32 Result = false; + PushSnapshot(Iter); + + ParseSignedness(Iter); + if (TokenAtEquals(Iter, "char")) + { + Result = true; + *TypeIndexOut = GetIndexOfType(MakeStringLiteral("char"), TypeTable); + } + else if (TokenAtEquals(Iter, "wchar_t")) + { + Result = true; + *TypeIndexOut = GetIndexOfType(MakeStringLiteral("wchar_t"), TypeTable); + } + + ApplySnapshotIfNotParsedAndPop(Result, Iter); + return Result; +} + +internal b32 +ParseBool(token_iter* Iter, s32* TypeIndexOut, type_table TypeTable) +{ + b32 Result = false; + PushSnapshot(Iter); + + if (TokenAtEquals(Iter, "bool")) + { + Result = true; + *TypeIndexOut = GetIndexOfType(MakeStringLiteral("bool"), TypeTable); + } + + ApplySnapshotIfNotParsedAndPop(Result, Iter); + return Result; +} + +internal b32 +ParseFloat(token_iter* Iter, s32* TypeIndexOut, type_table TypeTable) +{ + b32 Result = false; + PushSnapshot(Iter); + + if (TokenAtEquals(Iter, "float")) + { + Result = true; + *TypeIndexOut= GetIndexOfType(MakeStringLiteral("float"), TypeTable); + } + + ApplySnapshotIfNotParsedAndPop(Result, Iter); + return Result; +} + +internal b32 +ParseDouble(token_iter* Iter, s32* TypeIndexOut, type_table TypeTable) +{ + b32 Result = false; + PushSnapshot(Iter); + + if (TokenAtEquals(Iter, "double")) + { + Result = true; + *TypeIndexOut = GetIndexOfType(MakeStringLiteral("double"), TypeTable); + } + + ApplySnapshotIfNotParsedAndPop(Result, Iter); + return Result; +} + +// :UndeclaredType +// NOTE(Peter): If TypeIndexOut is -1, you need to call NextToken after this +// function to advance past the type identifier. +internal b32 +ParseType(token_iter* Iter, type_table* TypeTable, s32* TypeIndexOut) +{ + b32 Result = false; + *TypeIndexOut = -1; + PushSnapshot(Iter); + + if (ParseChar(Iter, TypeIndexOut, *TypeTable) || + ParseBool(Iter, TypeIndexOut, *TypeTable) || + LongLongInt(Iter, TypeIndexOut, *TypeTable) || + LongInt(Iter, TypeIndexOut, *TypeTable) || + ShortInt(Iter, TypeIndexOut, *TypeTable) || + Int(Iter, TypeIndexOut, *TypeTable) || + ParseFloat(Iter, TypeIndexOut, *TypeTable) || + ParseDouble(Iter, TypeIndexOut, *TypeTable)) + { + Result = true; + } + else if (StringsEqual(Iter->TokenAt->Text, MakeStringLiteral("void"))) + { + NextToken(Iter); + Result = true; + *TypeIndexOut = GetIndexOfType(MakeStringLiteral("void"), *TypeTable); + } + else + { + *TypeIndexOut = GetIndexOfType(Iter->TokenAt->Text, *TypeTable); + if (*TypeIndexOut >= 0) + { + Result = true; + NextToken(Iter); + } + else if(Iter->TokenAt->Type == Token_Identifier) + { + Result = true; + // NOTE(Peter): In this case, we believe we are at a type identifier, + // however, it hasn't been declared yet. This is due to the fact that we + // tokenize files, then parse them, then import the files they include, and + // then begin tokenizing, parsing, etc for those files. + // In the case that we get an as-of-yet undeclared type, we leave it + // up to the calling site to determine what to do with that information + // :UndeclaredType + *TypeIndexOut = -1; + } + } + + ApplySnapshotIfNotParsedAndPop(Result, Iter); + return Result; +} + +internal b32 +ParsePointer (token_iter* Iter) +{ + b32 Result = false; + if (TokenAtEquals(Iter, "*")) + { + Result = true; + } + return Result; +} + +internal b32 +ParseConstVolatile (token_iter* Iter) +{ + b32 Result = false; + PushSnapshot(Iter); + + if (TokenAtEquals(Iter, "volatile") || + TokenAtEquals(Iter, "const")) + { + Result = true; + } + + ApplySnapshotIfNotParsedAndPop(Result, Iter); + return Result; +} + +internal b32 +ParseVariableDecl(token_iter* Iter, gs_bucket* TagList, gs_bucket* VariableList, type_table* TypeTable) +{ + b32 Result = false; + PushSnapshot(Iter); + + if (ParseConstVolatile(Iter)) + { + // NOTE(Peter): we don't do anything with this atm + // dont have a reason to just yet + // :UnusedConstVolatile + } + + s32 TypeIndex = -1; + if (ParseType(Iter, TypeTable, &TypeIndex)) + { + // :UndeclaredType + if (TypeIndex < 0) + { + TypeIndex = PushUndeclaredType(Iter->TokenAt->Text, TypeTable); + NextToken(Iter); + } + + b32 IsPointer = ParsePointer(Iter); + + if (ParseConstVolatile(Iter)) + { + // :UnusedConstVolatile + } + + do { + token IdentifierToken = {}; + if (TokenAtEquals(Iter, Token_Identifier, &IdentifierToken)) { - ParseResult = ParseFunctionDeclaration(CurrentNode, CurrentToken); - CurrentToken = ParseResult.NextToken; - } - else - { - CurrentToken = CurrentToken->Next; - } - - if (ParseResult.Parsed) - { - if (CurrentNode == 0) + // Array Notationg ie r32 x[2]; + // NOTE(Peter): True initially because if there is no array notation, we + // are still ok to proceed + b32 ArrayParseSuccess = true; + u32 ArrayCount = 0; + if (TokenAtEquals(Iter, "[")) { - Ast.Children = ParseResult.Node; - CurrentNode = Ast.Children; + // NOTE(Peter): Once we get to this point, we have to complete the entire + // array notation before we have successfully parsed, hence setting + // ArrayParseSucces to false here. + ArrayParseSuccess = false; + token NumberToken = {}; + if (TokenAtEquals(Iter, Token_Number, &NumberToken)) + { + parse_result ParseArrayCount = ParseUnsignedInt(StringExpand(NumberToken.Text)); + ArrayCount = ParseArrayCount.UnsignedIntValue; + + if (TokenAtEquals(Iter, "]")) + { + ArrayParseSuccess = true; + } + } + } + + if (ArrayParseSuccess) + { + Result = true; + + variable_decl* Decl = VariableList->TakeElement(); + *Decl = {}; + Decl->Identifier = IdentifierToken.Text; + Decl->TypeIndex = TypeIndex; + Decl->Pointer = IsPointer; + Decl->ArrayCount = ArrayCount; + CopyMetaTagsAndClear(TagList, &Decl->MetaTags); + } + } + } while (TokenAtEquals(Iter, ",")); + } + + ApplySnapshotIfNotParsedAndPop(Result, Iter); + return Result; +} + +internal b32 +StructOrUnion(token_iter* Iter, type_definition_type* Type) +{ + b32 Result = false; + if (TokenAtEquals(Iter, "struct")) + { + Result = true; + *Type = TypeDef_Struct; + } + else if (TokenAtEquals(Iter, "union")) + { + Result = true; + *Type = TypeDef_Union; + } + return Result; +} + +internal b32 +ParseStruct(token_iter* Iter, s32* StructTypeIndexOut, gs_bucket* TagList, type_table* TypeTable) +{ + b32 Result = false; + *StructTypeIndexOut = -1; + + PushSnapshot(Iter); + + type_definition_type DeclType; + if (StructOrUnion(Iter, &DeclType)) + { + token IdentifierToken = {}; + if (TokenAtEquals(Iter, Token_Identifier, &IdentifierToken)) {} + + // TODO(Peter): Handle name coming after the struct + if (TokenAtEquals(Iter, "{")) + { + type_definition StructDecl = {}; + StructDecl.Identifier = IdentifierToken.Text; + StructDecl.Type = DeclType; + CopyMetaTagsAndClear(TagList, &StructDecl.MetaTags); + + while (!TokenAtEquals(Iter, "}")) + { + s32 MemberStructTypeIndex = {}; + variable_decl MemberDecl = {}; + if (ParseMetaTag(Iter, TagList)) + { + + } + else if (ParseVariableDecl(Iter, TagList, &StructDecl.Struct.MemberDecls, TypeTable)) + { + if (!TokenAtEquals(Iter, ";")) + { + PushFError(Iter->Errors, "No semicolon after struct member variable declaration. %S", StructDecl.Identifier); + } + } + else if (ParseStruct(Iter, &MemberStructTypeIndex, TagList, TypeTable)) + { + // NOTE(Peter): Pretty sure, since we just parsed the struct, that + // MemberStructTypeIndex should never be -1 (unknown type). + // Putting this Assert here for now, but remove if there's a valid + // reason that you might not be able to find a struct just parsed at + // this point. + Assert(MemberStructTypeIndex >= 0); + + MemberDecl.TypeIndex = MemberStructTypeIndex; + StructDecl.Struct.MemberDecls.PushElementOnBucket(MemberDecl); } else { - CurrentNode->Next = ParseResult.Node; - CurrentNode = CurrentNode->Next; + // NOTE(Peter): One of the things that falls through here is + // cpp template stuff. Eventually, we should be able to use + // this meta layer to get rid of them all together, and then + // we can just disallow CPP templates + NextToken(Iter); } } + + if (TokenAtEquals(Iter, ";")) + { + Result = true; + *StructTypeIndexOut = PushTypeDefOnTypeTable(StructDecl, TypeTable); + } + } + } + + ApplySnapshotIfNotParsedAndPop(Result, Iter); + return Result; +} + +// ( type *? identifier, ... ) +internal b32 +ParseFunctionParameterList (token_iter* Iter, type_definition* FunctionPtrDecl, gs_bucket* TagList, type_table* TypeTable) +{ + b32 Result = false; + PushSnapshot(Iter); + + if (TokenAtEquals(Iter, "(")) + { + Result = true; + + while(!StringsEqual(Iter->TokenAt->Text, MakeStringLiteral(")"))) + { + if (ParseVariableDecl(Iter, TagList, &FunctionPtrDecl->FunctionPtr.Parameters, TypeTable)) + { + if (TokenAtEquals(Iter, Token_Comma)) + { + } + else if (!StringsEqual(Iter->TokenAt->Text, MakeStringLiteral(")"))) + { + Result = false; + break; + } + } + } + + if (TokenAtEquals(Iter, ")")) + { + Result = true; + } + } + + ApplySnapshotIfNotParsedAndPop(Result, Iter); + return Result; +} + +internal b32 +ParseFunctionDeclaration (token_iter* Iter, token* Identifier, gs_bucket* TagList, type_table* TypeTable) +{ + b32 Result = false; + PushSnapshot(Iter); + + s32 ReturnTypeIndex = -1; + if (ParseType(Iter, TypeTable, &ReturnTypeIndex)) + { + if (ReturnTypeIndex < 0) + { + ReturnTypeIndex = PushUndeclaredType(Iter->TokenAt->Text, TypeTable); + NextToken(Iter); + } + + b32 IsPointer = ParsePointer(Iter); + + if (TokenAtEquals(Iter, Token_Identifier, Identifier)) + { + type_definition FunctionPtr = {}; + FunctionPtr.Identifier = Identifier->Text; + FunctionPtr.Size = sizeof(void*); + CopyMetaTagsAndClear(TagList, &FunctionPtr.MetaTags); + FunctionPtr.Type = TypeDef_FunctionPointer; + FunctionPtr.Pointer = true; + FunctionPtr.FunctionPtr = {}; + FunctionPtr.FunctionPtr.ReturnTypeIndex = ReturnTypeIndex; + + if (ParseFunctionParameterList(Iter, &FunctionPtr, TagList, TypeTable)) + { + if (TokenAtEquals(Iter, ";")) + { + Result = true; + PushTypeDefOnTypeTable(FunctionPtr, TypeTable); + } + } + } + } + + ApplySnapshotIfNotParsedAndPop(Result, Iter); + if (!Result) + { + *Identifier = {0}; + } + return Result; +} + +internal b32 +ParseTypedef(token_iter* Iter, gs_bucket* TagList, type_table* TypeTable) +{ + b32 Result = false; + PushSnapshot(Iter); + + if (TokenAtEquals(Iter, "typedef")) + { + token TypeToken = {0}; + s32 TypeIndex = -1; + if (TokenAtEquals(Iter, "struct") && + ParseStruct(Iter, &TypeIndex, TagList, TypeTable)) + { + Result = true; + } + else if (ParseFunctionDeclaration(Iter, &TypeToken, TagList, TypeTable)) + { + Result = true; + } + else if (ParseType(Iter, TypeTable, &TypeIndex)) + { + if (TypeIndex < 0) + { + TypeIndex = PushUndeclaredType(Iter->TokenAt->Text, TypeTable); + NextToken(Iter); + } + + b32 IsPointer = ParsePointer(Iter); + + type_definition* BasisType = TypeTable->Types.GetElementAtIndex(TypeIndex); + + type_definition NewType = {}; + NewType.Size = BasisType->Size; + CopyMetaTagsAndClear(TagList, &NewType.MetaTags); + NewType.Type = BasisType->Type; + if (NewType.Type == TypeDef_Struct || + NewType.Type == TypeDef_Union) + { + NewType.Struct = BasisType->Struct; + } + NewType.Pointer = BasisType->Pointer || IsPointer; + + token IdentifierToken = {}; + if (TokenAtEquals(Iter, Token_Identifier, &IdentifierToken)) + { + NewType.Identifier = IdentifierToken.Text; + PushTypeDefOnTypeTable(NewType, TypeTable); + Result = true; + } } else { - CurrentToken = CurrentToken->Next; + string* Error = TakeError(Iter->Errors); + PrintF(Error, "unhandled typedef "); + while (!TokenAtEquals(Iter, ";")) + { + PrintF(Error, "%S ", Iter->TokenAt->Text); + NextToken(Iter); + } + PrintF(Error, "\n"); } } - string_partition StringPart = {}; - { - memory_arena StringMemory = {}; - InitMemoryArena(&StringMemory, (u8*)malloc(Megabytes(4)), Megabytes(4)); - InitStringPartition(&StringPart, &StringMemory); - } - // Print Structs - ast_node* Node = Ast.Children; - while (Node) - { - switch (Node->Type) - { - case ASTNode_StructDeclaration: - { - string_buffer* CodeBuffer = GenerateStructCode(Node, &StringPart); - PrintStringBuffer(CodeBuffer); - }break; - - case ASTNode_FunctionDeclaration: - { - string_buffer* CodeBuffer = GenerateFunctionDeclaration(Node, &StringPart); - PrintStringBuffer(CodeBuffer); - }break; - } - - Node = Node->Next; - } - - return 0; + ApplySnapshotIfNotParsedAndPop(Result, Iter); + return Result; } -int main(int ArgCount, char** ArgV) +internal b32 +ParseEnum (token_iter* Iter, gs_bucket* TagList, type_table* TypeTable) { - if (ArgCount <= 1) + b32 Result = false; + PushSnapshot(Iter); + + if (TokenAtEquals(Iter, "enum")) { - printf("Please supply at least one source directory to analyze.\n"); - return 0; + token IdentifierToken = {}; + if (TokenAtEquals(Iter, Token_Identifier, &IdentifierToken)) + { + type_definition EnumDecl = {}; + EnumDecl.Identifier = IdentifierToken.Text; + EnumDecl.Size = sizeof(u32); + CopyMetaTagsAndClear(TagList, &EnumDecl.MetaTags); + EnumDecl.Type = TypeDef_Enum; + + if (TokenAtEquals(Iter, "{")) + { + u32 EnumAcc = 0; + + while (!StringsEqual(Iter->TokenAt->Text, MakeStringLiteral("}"))) + { + token EnumIdentifierToken = {}; + if (TokenAtEquals(Iter, Token_Identifier, &EnumIdentifierToken)) + { + if (TokenAtEquals(Iter, "=")) + { + // TODO(Peter): TempValue is just here until we handle all + // const expr that could define an enum value. Its there so + // that if the first token of an expression is a number, + // we can avoid using anything from the expression. + u32 TempValue = EnumAcc; + token NumberToken = {}; + if (TokenAtEquals(Iter, Token_Number, &NumberToken)) + { + parse_result ParsedExpr = ParseSignedInt(StringExpand(NumberToken.Text)); + TempValue = ParsedExpr.SignedIntValue; + } + + // TODO(Peter): Handle setting enums equal to other kinds + // of const exprs. + // We're skipping a whole bunch of stuff now + while (!(StringsEqual(Iter->TokenAt->Text, MakeStringLiteral(",")) || + StringsEqual(Iter->TokenAt->Text, MakeStringLiteral("}")))) + { + TempValue = EnumAcc; + NextToken(Iter); + } + + EnumAcc = TempValue; + } + + s32 EnumValue = EnumAcc++; + if (TokenAtEquals(Iter, ",") || + StringsEqual(Iter->TokenAt->Text, MakeStringLiteral("}"))) + { + EnumDecl.Enum.Identifiers.PushElementOnBucket(EnumIdentifierToken.Text); + EnumDecl.Enum.Values.PushElementOnBucket(EnumValue); + } + else if (!StringsEqual(Iter->TokenAt->Text, MakeStringLiteral("}"))) + { + Result = false; + break; + } + } + } + + if (TokenAtEquals(Iter, "}") && + TokenAtEquals(Iter, ";")) + { + PushTypeDefOnTypeTable(EnumDecl, TypeTable); + Result = true; + } + } + } } - TCHAR Win32FileNameBuffer[MAX_PATH]; - char FullFilePath[MAX_PATH]; - - for (int i = 1; i < ArgCount; i++) + ApplySnapshotIfNotParsedAndPop(Result, Iter); + return Result; +} + +internal void +PrintIndent (u32 Indent) +{ + for (u32 i = 0; i < Indent; i++) { - WIN32_FIND_DATA FindFileData; - - StringCchCopy(Win32FileNameBuffer, MAX_PATH, ArgV[i]); - StringCchCat(Win32FileNameBuffer, MAX_PATH, TEXT("\\*")); - - HANDLE CurrentFile = FindFirstFile(Win32FileNameBuffer, &FindFileData); - - int FileIdx = 0; - do { - if (FindFileData.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY) { - // TODO(Peter): Recurse? - continue; - } - - printf("File %d: %s\n", FileIdx++, FindFileData.cFileName); - - - } while (FindNextFile(CurrentFile, &FindFileData)); + printf(" "); } } -#endif \ No newline at end of file + +internal void PrintStructDecl (type_definition* StructDecl, type_table TypeTable, u32 Indent); + +internal void +PrintVariableDecl (variable_decl Member, type_table TypeTable, u32 Indent = 0) +{ + type_definition* MemberTypeDef = TypeTable.Types.GetElementAtIndex(Member.TypeIndex); + if ((MemberTypeDef->Type == TypeDef_Struct || MemberTypeDef->Type == TypeDef_Union) + && MemberTypeDef->Identifier.Length == 0) + { + PrintStructDecl(MemberTypeDef, TypeTable, Indent); + } + else + { + PrintIndent(Indent); + if (Member.TypeIndex == -1) + { + printf("???? "); + } + printf("%.*s ", StringExpand(MemberTypeDef->Identifier)); + } + + if (Member.Pointer) + { + printf("* "); + } + + printf("%.*s", StringExpand(Member.Identifier)); + + if (Member.ArrayCount > 0) + { + printf("[%d]", Member.ArrayCount); + } +} + +internal void +PrintStructDecl (type_definition* StructDecl, type_table TypeTable, u32 Indent = 0) +{ + Assert(StructDecl->Type == TypeDef_Struct || + StructDecl->Type == TypeDef_Union); + + PrintIndent(Indent); + if (StructDecl->Type == TypeDef_Struct) + { + printf("struct "); + } + else if (StructDecl->Type == TypeDef_Union) + { + printf("union "); + } + else { InvalidCodePath; } + + if (StructDecl->Identifier.Length > 0) + { + printf("%.*s ", StringExpand(StructDecl->Identifier)); + } + printf("{\n"); + + for (u32 MemberIndex = 0; MemberIndex < StructDecl->Struct.MemberDecls.Used; MemberIndex++) + { + variable_decl* Member = StructDecl->Struct.MemberDecls.GetElementAtIndex(MemberIndex); + PrintVariableDecl(*Member, TypeTable, Indent + 1); + printf(";\n"); + } + PrintIndent(Indent); + printf("} ( size = %d ) ", StructDecl->Size); +} + +internal void +PrintFunctionPtrDecl (type_definition* FnPtrDecl, type_table TypeTable) +{ + type_definition* ReturnType = TypeTable.Types.GetElementAtIndex(FnPtrDecl->FunctionPtr.ReturnTypeIndex); + printf("%.*s ", StringExpand(ReturnType->Identifier)); + + if (FnPtrDecl->Identifier.Length > 0) + { + printf("%.*s ", StringExpand(FnPtrDecl->Identifier)); + } + printf("("); + + for (u32 MemberIndex = 0; MemberIndex < FnPtrDecl->FunctionPtr.Parameters.Used; MemberIndex++) + { + variable_decl* Param = FnPtrDecl->FunctionPtr.Parameters.GetElementAtIndex(MemberIndex); + PrintVariableDecl(*Param, TypeTable, 0); + printf(", "); + } + + printf(");"); +} + +internal gs_meta_preprocessor +PreprocessProgram (char* SourceFile) +{ + gs_meta_preprocessor Meta = {}; + + Meta.PreprocessorStartTime = GetWallClock(); + + PopulateTableWithDefaultCPPTypes(&Meta.TypeTable); + + string CurrentWorkingDirectory = MakeString((char*)malloc(1024), 0, 1024); + + string RootFile = MakeString(SourceFile); + AddFileToSource(RootFile, &Meta.SourceFiles, &Meta.Errors); + + s32 LastSlash = ReverseSearchForCharInSet(RootFile, "\\/"); + if (LastSlash <= 0) + { + PushFError(&Meta.Errors, "%S: File path invalid.", RootFile); + return Meta; + } + + string RootPath = Substring(RootFile, 0, LastSlash + 1); + CopyStringTo(RootPath, &CurrentWorkingDirectory); + + for (u32 SourceFileIdx = 0; SourceFileIdx < Meta.SourceFiles.Used; SourceFileIdx++) + { + source_code_file* File = Meta.SourceFiles.GetElementAtIndex(SourceFileIdx); + TokenizeFile(File, &Meta.Tokens); + + token_iter Iter = {}; + Iter.Tokens = &Meta.Tokens; + Iter.FirstToken = File->FirstTokenIndex; + Iter.LastToken = File->LastTokenIndex; + Iter.TokenAtIndex = Iter.FirstToken; + Iter.TokenAt = Meta.Tokens.GetElementAtIndex(Iter.TokenAtIndex); + Iter.Errors = &Meta.Errors; + + while (Iter.TokenAtIndex < Iter.LastToken) + { + b32 ParseSuccess = false; + + s32 TypeIndex = -1; + if (TokenAtEquals(&Iter, "#include")) + { + token* IncludeFile = Iter.TokenAt; + + // NOTE(Peter): For now we aren't going in and preprocessing the header files + // we include from the system + // Token_Operator is used to check if the include is of the form '#include ' + // and skip it. + // TODO(Peter): This is only a rough approximation of ignoring system headers + // TODO(Peter): We should actually see what parsing system headers would entail + if (IncludeFile->Type != Token_Operator) + { + string TempFilePath = IncludeFile->Text; + + // NOTE(Peter): if the path is NOT absolute ie "C:\etc + if (!(IsAlpha(TempFilePath.Memory[0]) && + TempFilePath.Memory[1] == ':' && + TempFilePath.Memory[2] == '\\')) + { + TempFilePath = CurrentWorkingDirectory; + ConcatString(IncludeFile->Text, &TempFilePath); + NullTerminate(&TempFilePath); + } + + ParseSuccess = true; + if (!FileAlreadyInSource(TempFilePath, Meta.SourceFiles)) + { + AddFileToSource(TempFilePath, &Meta.SourceFiles, &Meta.Errors); + } + } + } + else if(ParseMetaTag(&Iter, &Meta.TagList)) + { + ParseSuccess = true; + } + else if (ParseEnum(&Iter, &Meta.TagList, &Meta.TypeTable)) + { + ParseSuccess = true; + } + else if (ParseStruct(&Iter, &TypeIndex, &Meta.TagList, &Meta.TypeTable)) + { + ParseSuccess = true; + } + else if (ParseTypedef(&Iter, &Meta.TagList, &Meta.TypeTable)) + { + ParseSuccess = true; + } + + if (!ParseSuccess) + { + NextToken(&Iter); + } + } + } + + // Type Table Fixup + for (u32 i = 0; i < Meta.TypeTable.Types.Used; i++) + { + type_definition* TypeDef = Meta.TypeTable.Types.GetElementAtIndex(i); + if (TypeDef->Type == TypeDef_Struct) + { + FixUpStructSize(i, Meta.TypeTable, &Meta.Errors); + } + else if (TypeDef->Type == TypeDef_Union) + { + FixUpUnionSize(i, Meta.TypeTable, &Meta.Errors); + } + } + + Meta.PreprocessorEndTime = GetWallClock(); + return Meta; +} + +internal void +FinishMetaprogram(gs_meta_preprocessor* Meta) +{ + PrintAllErrors(Meta->Errors); + + s64 TotalEnd = GetWallClock(); + r32 PreprocTime = GetSecondsElapsed(Meta->PreprocessorStartTime, Meta->PreprocessorEndTime); + r32 TotalTime = GetSecondsElapsed(Meta->PreprocessorStartTime, TotalEnd); + r32 UserTime = TotalTime - PreprocTime; + printf("Metaprogram Performance:\n"); + printf(" Preproc Time: %.*f sec\n", 6, PreprocTime); + printf(" Custom Time: %.*f sec\n", 6, UserTime); + printf(" Total Time: %.*f sec\n", 6, TotalTime); + +} diff --git a/meta/gs_meta_error.h b/meta/gs_meta_error.h index ae110a0..2648959 100644 --- a/meta/gs_meta_error.h +++ b/meta/gs_meta_error.h @@ -1,98 +1,68 @@ -#define MAX_ERROR_LENGTH 256 -struct error +struct error_buffer { - char Backbuffer[MAX_ERROR_LENGTH]; - string Buffer; + char* Backbuffer; + string* Contents; }; -struct error_list_buffer +#define ERROR_MAX_LENGTH 256 +#define ERROR_BUFFER_SIZE 256 +struct errors { - error* List; - s32 Used; - s32 Max; - error_list_buffer* Next; + error_buffer* Buffers; + u32 BuffersCount; + u32 Used; }; -struct error_list +internal void +PushFError (errors* Errors, char* Format, ...) { - error_list_buffer* Head; - s32 TotalUsed; - s32 TotalMax; -}; - -#define ERROR_LIST_GROW_SIZE 32 - -internal void -GrowErrorList (error_list* Errors) -{ - Assert(Errors); - - s32 ExtensionSize = sizeof(error_list_buffer) + (sizeof(error) * ERROR_LIST_GROW_SIZE); - u8* ExtensionMemory = (u8*)malloc(ExtensionSize); - - error_list_buffer* Extension = (error_list_buffer*)ExtensionMemory; - Extension->Used = 0; - Extension->Max = ERROR_LIST_GROW_SIZE; - Extension->List = (error*)(ExtensionMemory + sizeof(error_list_buffer)); - - Extension->Next = Errors->Head; - Errors->Head = Extension; - - Errors->TotalMax += ERROR_LIST_GROW_SIZE; -} - -#define ErrorAssert(condition, list, format, ...) \ -if (!(condition)) { LogError_((list), __FILE__, __LINE__, (format), __VA_ARGS__); } - -#define LogError(list, format, ...) LogError_((list), __FILE__, __LINE__, (format), __VA_ARGS__) - -internal void -LogError_ (error_list* Errors, char* File, s32 Line, char* Format, ...) -{ - if (Errors->TotalUsed >= Errors->TotalMax) + if (Errors->Used >= (Errors->BuffersCount * ERROR_BUFFER_SIZE)) { - GrowErrorList(Errors); + Errors->BuffersCount += 1; + Errors->Buffers = (error_buffer*)realloc(Errors->Buffers, sizeof(error_buffer*) * Errors->BuffersCount); + + error_buffer* NewBuffer = Errors->Buffers + (Errors->BuffersCount - 1); + NewBuffer->Backbuffer = (char*)malloc(sizeof(char) * ERROR_MAX_LENGTH * ERROR_BUFFER_SIZE); + NewBuffer->Contents = (string*)malloc(sizeof(string) * ERROR_BUFFER_SIZE); + + for (u32 i = 0; i < ERROR_BUFFER_SIZE; i++) + { + NewBuffer->Contents[i].Memory = NewBuffer->Backbuffer + (i * ERROR_MAX_LENGTH); + NewBuffer->Contents[i].Max = ERROR_MAX_LENGTH; + NewBuffer->Contents[i].Length = 0; + } } - error* Error = (Errors->Head->List + Errors->Head->Used++); - Errors->TotalUsed++; - - InitializeEmptyString(&Error->Buffer, Error->Backbuffer, MAX_ERROR_LENGTH); + u32 NewErrorIndex = Errors->Used++; + u32 BufferIndex = NewErrorIndex / ERROR_BUFFER_SIZE; + u32 IndexInBuffer = NewErrorIndex % ERROR_BUFFER_SIZE; + string* NewError = Errors->Buffers[BufferIndex].Contents + IndexInBuffer; va_list Args; va_start(Args, Format); - - PrintF(&Error->Buffer, "%s(%d): ", File, Line); - Error->Buffer.Length += PrintFArgsList(Error->Buffer.Memory + Error->Buffer.Length, - Error->Buffer.Max - Error->Buffer.Length, - Format, Args); - + NewError->Length = PrintFArgsList(NewError->Memory, NewError->Max, Format, Args); va_end(Args); } -internal void -PrintErrorListBuffer (error_list_buffer* Buffer) +internal string* +TakeError (errors* Errors) { - if (Buffer->Next) - { - PrintErrorListBuffer(Buffer->Next); - } - - for (s32 i = 0; i < Buffer->Used; i++) - { - error* Error = Buffer->List + i; - NullTerminate(&Error->Buffer); - printf(Error->Backbuffer); - printf("\n"); - } + u32 NewErrorIndex = Errors->Used++; + u32 BufferIndex = NewErrorIndex / ERROR_BUFFER_SIZE; + u32 IndexInBuffer = NewErrorIndex % ERROR_BUFFER_SIZE; + string* NewError = Errors->Buffers[BufferIndex].Contents + IndexInBuffer; + return NewError; } internal void -PrintErrorList (error_list Errors) +PrintAllErrors (errors Errors) { - if (Errors.Head) + for (u32 i = 0; i < Errors.Used; i++) { - PrintErrorListBuffer(Errors.Head); + u32 BufferIndex = i / ERROR_BUFFER_SIZE; + u32 IndexInBuffer = i % ERROR_BUFFER_SIZE; + string Error = Errors.Buffers[BufferIndex].Contents[IndexInBuffer]; + printf("%.*s\n", StringExpand(Error)); } -} \ No newline at end of file +} diff --git a/meta/gs_meta_typeinfo_generator.h b/meta/gs_meta_typeinfo_generator.h new file mode 100644 index 0000000..dc4cca5 --- /dev/null +++ b/meta/gs_meta_typeinfo_generator.h @@ -0,0 +1,168 @@ +// +// File: gs_meta_typeinfo_generator.h +// Author: Peter Slattery +// Creation Date: 2020-01-19 +// +#ifndef GS_META_TYPEINFO_GENERATOR_H + +#include +#include +#include + +struct typeinfo_generator +{ + string_builder TypeList; + string_builder StructMembers; + string_builder TypeDefinitions; + + u32 GeneratedInfoTypesCount; + u32 TypesMax; + b8* TypesGeneratedMask; +}; + +internal typeinfo_generator +InitTypeInfoGenerator(type_table TypeTable) +{ + typeinfo_generator Result = {}; + + Result.TypesMax = TypeTable.Types.Used; + Result.TypesGeneratedMask = (b8*)malloc(sizeof(b8) * Result.TypesMax); + GSZeroMemory((u8*)Result.TypesGeneratedMask, Result.TypesMax); + + WriteF(&Result.TypeList, "enum gsm_struct_type\n{\n"); + + WriteF(&Result.TypeDefinitions, "static gsm_struct_type_info StructTypes[] = {\n"); + return Result; +} + +internal void +FinishGeneratingTypes(typeinfo_generator* Generator) +{ + WriteF(&Generator->TypeList, "gsm_StructTypeCount,\n};\n\n"); + + WriteF(&Generator->StructMembers, "\n"); + + WriteF(&Generator->TypeDefinitions, "};\n"); + WriteF(&Generator->TypeDefinitions, "gsm_u32 StructTypesCount = %d;\n", Generator->GeneratedInfoTypesCount); +} + +internal void +GenerateMetaTagInfo (gs_bucket Tags, string_builder* Builder) +{ + WriteF(Builder, "{"); + for (u32 t = 0; t < Tags.Used; t++) + { + meta_tag* Tag = Tags.GetElementAtIndex(t); + WriteF(Builder, "{ \"%S\", %d }", Tag->Identifier, Tag->Identifier.Length); + if ((t + 1) < Tags.Used) + { + WriteF(Builder, ", "); + } + } + WriteF(Builder, "}, %d", Tags.Used); +} + +internal void +GenerateStructMemberInfo (variable_decl* Member, string StructIdentifier, type_table TypeTable, typeinfo_generator* Gen) +{ + WriteF(&Gen->StructMembers, "{ \"%S\", %d, ", Member->Identifier, Member->Identifier.Length); + WriteF(&Gen->StructMembers, "(u64)&((%S*)0)->%S ", StructIdentifier, Member->Identifier); + WriteF(&Gen->StructMembers, "},\n"); +} + +internal void +GenerateTypeInfo (type_definition* Type, u32 TypeIndex, type_table TypeTable, typeinfo_generator* Generator) +{ + Generator->TypesGeneratedMask[TypeIndex] = true; + Generator->GeneratedInfoTypesCount++; + + { + // NOTE(Peter): This block MUST come before generating + // type info for any member types. If it doesn't, it will screw + // up array ordering + + // Lookup Enum + WriteF(&Generator->TypeList, "gsm_StructType_%S,\n", Type->Identifier); + + // Type Info + WriteF(&Generator->TypeDefinitions, "{ gsm_StructType_%S, \"%S\", %d, %d, 0, 0, ", + Type->Identifier, + Type->Identifier, Type->Identifier.Length, + Type->Size + // TODO(Peter): include Meta Tags somehow + ); + if ((Type->Type == TypeDef_Struct || Type->Type == TypeDef_Union) && + Type->Struct.MemberDecls.Used > 0) + { + WriteF(&Generator->TypeDefinitions, "StructMembers_%S, %d },\n", + Type->Identifier, + Type->Struct.MemberDecls.Used); + } + else + { + WriteF(&Generator->TypeDefinitions, "0, 0 },\n"); + } + } + + if (Type->Type == TypeDef_Struct || + Type->Type == TypeDef_Union) + { + for (u32 m = 0; m < Type->Struct.MemberDecls.Used; m++) + { + variable_decl* Member = Type->Struct.MemberDecls.GetElementAtIndex(m); + type_definition* MemberType = TypeTable.Types.GetElementAtIndex(Member->TypeIndex); + + if (MemberType->Identifier.Length == 0) { continue; } // Don't gen info for anonymous struct and union members + if (Generator->TypesGeneratedMask[Member->TypeIndex]) { continue; } + + GenerateTypeInfo(MemberType, Member->TypeIndex, TypeTable, Generator); + } + + // + WriteF(&Generator->StructMembers, "static gsm_struct_member_type_info StructMembers_%S[] = {\n", Type->Identifier); + for (u32 m = 0; m < Type->Struct.MemberDecls.Used; m++) + { + variable_decl* Member = Type->Struct.MemberDecls.GetElementAtIndex(m); + type_definition* MemberType = TypeTable.Types.GetElementAtIndex(Member->TypeIndex); + + if (MemberType->Identifier.Length > 0) + { + GenerateStructMemberInfo(Member, Type->Identifier, TypeTable, Generator); + } + else if (MemberType->Type == TypeDef_Struct || + MemberType->Type == TypeDef_Union) + { + // Anonymous Members + for (u32 a = 0; a < MemberType->Struct.MemberDecls.Used; a++) + { + variable_decl* AnonMember = MemberType->Struct.MemberDecls.GetElementAtIndex(a); + GenerateStructMemberInfo(AnonMember, Type->Identifier, TypeTable, Generator); + } + } + } + WriteF(&Generator->StructMembers, "};\n", Type->Struct.MemberDecls.Used); + } +} + +internal void +GenerateFilteredTypeInfo (string MetaTagFilter, type_table TypeTable, typeinfo_generator* Generator) +{ + for (u32 i = 0; i < TypeTable.Types.Used; i++) + { + if (Generator->TypesGeneratedMask[i]) + { + continue; + } + + type_definition* Type = TypeTable.Types.GetElementAtIndex(i); + if (HasTag(MetaTagFilter, Type->MetaTags)) + { + GenerateTypeInfo(Type, i, TypeTable, Generator); + } + } +} + + + +#define GS_META_TYPEINFO_GENERATOR_H +#endif // GS_META_TYPEINFO_GENERATOR_H \ No newline at end of file