Refactored how logging works

Made it central reusable logic. No longer needs to be passed around, opened or closed.
This commit is contained in:
Pasha Bibko
2025-05-05 23:55:22 +01:00
parent 0f11fe006b
commit 5339df9b36
22 changed files with 231 additions and 193 deletions

View File

@@ -158,7 +158,9 @@
<ClInclude Include="LX-Common.h" /> <ClInclude Include="LX-Common.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="src\Console.cpp" />
<ClCompile Include="src\dllmain.cpp" /> <ClCompile Include="src\dllmain.cpp" />
<ClCompile Include="src\Logger.cpp" />
<ClCompile Include="src\pch.cpp"> <ClCompile Include="src\pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>

View File

@@ -37,5 +37,11 @@
<ClCompile Include="src\pch.cpp"> <ClCompile Include="src\pch.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="src\Logger.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\Console.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -11,7 +11,8 @@
#define NOMINMAX #define NOMINMAX
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <Windows.h> #include <Windows.h>
#undef NOMINMAX
#undef WIN32_LEAN_AND_MEAN
// Else alerts the user that their system is not supported // // Else alerts the user that their system is not supported //
#else #else
#error "This code is only designed to work on windows" #error "This code is only designed to work on windows"
@@ -22,6 +23,17 @@
#error "This code is only designed to work with Visual Studio" #error "This code is only designed to work with Visual Studio"
#endif // _MSC_VER #endif // _MSC_VER
// My commonly used macros //
#define RETURN_IF(condition) if (condition) { return; }
#define RETURN_V_IF(value, condition) if (condition) { return value; }
#ifdef COMMON_EXPORTS
#define COMMON_API __declspec(dllexport)
#else
#define COMMON_API __declspec(dllimport)
#endif // COMMON_EXPORTS
// Includes commonly used STD files // // Includes commonly used STD files //
#include <unordered_map> #include <unordered_map>

View File

@@ -1,41 +1,30 @@
namespace LX namespace LX
{ {
// Enum of colors with their Win32 equivalent value //
enum class Color enum class Color
{ {
BLACK = 0, BLACK = 0,
BLUE = 1, BLUE = 1,
GREEN = 2, GREEN = 2,
AQUA = 3, AQUA = 3,
RED = 4, RED = 4,
PURPLE = 5, PURPLE = 5,
YELLOW = 6, YELLOW = 6,
LIGHT_GRAY = 7, LIGHT_GRAY = 7,
LIGHT_BLUE = 9, LIGHT_BLUE = 9,
LIGHT_GREEN = 10, LIGHT_GREEN = 10,
LIGHT_AQUA = 11, LIGHT_AQUA = 11,
LIGHT_RED = 12, LIGHT_RED = 12,
LIGHT_PURPLE = 13, LIGHT_PURPLE = 13,
LIGHT_YELLOW = 14, LIGHT_YELLOW = 14,
WHITE = 15 WHITE = 15
}; };
inline void PrintStringAsColor(const std::string& str, Color c) // Prints a string to std::cout with a certain color using Win32 API //
{ extern "C" void COMMON_API PrintStringAsColor(const std::string& str, Color c);
// Gets a handle to the console //
static HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
// Sets the color of the console to the desired color //
SetConsoleTextAttribute(hConsole, (WORD)c);
// Outputs the text //
std::cout << str;
// Resets the color //
SetConsoleTextAttribute(hConsole, (WORD)Color::LIGHT_GRAY);
}
// Util function for getting a line of the source at a given index (used for errors) // // Util function for getting a line of the source at a given index (used for errors) //
inline std::string GetLineAtIndexOf(const std::string src, const std::streamsize index) inline std::string GetLineAtIndexOf(const std::string& src, const std::streamsize index) // <- Has to be inline because of C++ types
{ {
// Finds the start of the line // // Finds the start of the line //
size_t start = src.rfind('\n', index); size_t start = src.rfind('\n', index);

View File

@@ -1,23 +1,51 @@
namespace LX namespace LX
{ {
template<typename... Args> class COMMON_API Log
inline void SafeLog(std::ofstream* log, Args... args)
{ {
if (log != nullptr) public:
{ // This class should never be constructed //
(*log << ... << args); Log() = delete;
(*log << '\n');
}
}
inline void SafeFlush(std::ofstream* log) enum class Format
{ {
if (log != nullptr) AUTO,
{ NONE
log->flush(); };
}
}
// Gives a standard way to mark a change between different sections within the log output // template<Format format = Format::AUTO, typename... Args>
constexpr const char* LOG_BREAK = "\n-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n"; static void out(Args... args)
{
if constexpr (format == Format::AUTO)
{
((*s_LogFile << ... << args) << "\n");
}
else
{
(*s_LogFile << ... << args);
}
}
template<typename... Args>
static void LogNewSection(Args... args)
{
static const char* BREAK = "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-";
*s_LogFile << '\n' << BREAK << '\n';
(*s_LogFile << ... << args);
*s_LogFile << '\n' << BREAK << '\n';
}
private:
// Allows ProcAttach to manage the log //
friend bool ProcAttach(HMODULE hModule);
// Initalises the log (Called by DllMain) //
static void Init();
// Closes the log (Called by DllMain) //
static void Close();
static std::ofstream* s_LogFile;
};
} }

19
Common/src/Console.cpp Normal file
View File

@@ -0,0 +1,19 @@
#include <LX-Common.h>
namespace LX
{
void PrintStringAsColor(const std::string& str, Color c)
{
// Gets a handle to the console //
static HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
// Sets the color of the console to the desired color //
SetConsoleTextAttribute(hConsole, (WORD)c);
// Outputs the text //
std::cout << str;
// Resets the color //
SetConsoleTextAttribute(hConsole, (WORD)Color::LIGHT_GRAY);
}
}

26
Common/src/Logger.cpp Normal file
View File

@@ -0,0 +1,26 @@
#include <LX-Common.h>
namespace LX
{
// Allocates memory for the log file pointer //
std::ofstream* Log::s_LogFile = nullptr;
void Log::Init()
{
// The actual object holding the log file //
// Has to be done like this to stop MSVC complaining //
static std::ofstream actualLog;
// Opens the log file and assigns it to the log pointer //
actualLog.open("log");
s_LogFile = &actualLog;
}
void Log::Close()
{
// Flushes and closes the log //
// Yes I know closing automatically flushes but this function looked empty //
s_LogFile->flush();
s_LogFile->close();
}
}

View File

@@ -3,36 +3,38 @@
namespace LX namespace LX
{ {
// All the different functions that can be called by the system //
// Currently all empty but here for easier future development //
using DllFunc = bool(HMODULE); using DllFunc = bool(HMODULE);
static bool ProcAttach(HMODULE hModule) static bool ProcAttach(HMODULE hModule)
{ {
Log::Init(); // Initalises the log before the main process starts
return true;
} }
static bool ProcDetach(HMODULE hModule) static bool ProcDetach(HMODULE hModule)
{ {
return true;
} }
static bool ThreadAttach(HMODULE hModule) static bool ThreadAttach(HMODULE hModule) { return true; }
{ static bool ThreadDetach(HMODULE hModule) { return true; }
}
static bool ThreadDetach(HMODULE hModule)
{
}
} }
BOOL __stdcall DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) BOOL __stdcall DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{ {
switch (ul_reason_for_call) // All the functions that might be called with their relevant state //
static const std::unordered_map<DWORD, LX::DllFunc&> funcs =
{ {
case DLL_PROCESS_ATTACH: { DLL_PROCESS_ATTACH, LX::ProcAttach },
case DLL_THREAD_ATTACH: { DLL_PROCESS_DETACH, LX::ProcDetach },
case DLL_THREAD_DETACH: { DLL_THREAD_ATTACH , LX::ThreadAttach },
case DLL_PROCESS_DETACH: { DLL_THREAD_DETACH , LX::ThreadDetach }
break; };
}
return true; // Returns the output of the relavant function //
return funcs.at(ul_reason_for_call)(hModule);
} }

View File

@@ -122,7 +122,7 @@
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(SolutionDir)bin\$(Platform)\$(Configuration)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>$(SolutionDir)bin\$(Platform)\$(Configuration)</AdditionalLibraryDirectories>
<AdditionalDependencies>Parser.lib;Lexer.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>Parser.lib;Lexer.lib;Common.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@@ -144,7 +144,7 @@
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(SolutionDir)bin\$(Platform)\$(Configuration)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>$(SolutionDir)bin\$(Platform)\$(Configuration)</AdditionalLibraryDirectories>
<AdditionalDependencies>Parser.lib;Lexer.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>Parser.lib;Lexer.lib;Common.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
@@ -158,6 +158,11 @@
<ClInclude Include="inc\Lexer.h" /> <ClInclude Include="inc\Lexer.h" />
<ClInclude Include="inc\Parser.h" /> <ClInclude Include="inc\Parser.h" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Common\Common.vcxproj">
<Project>{0abb03b7-e61a-4040-a512-fc05aa35b2a6}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
</ImportGroup> </ImportGroup>

View File

@@ -128,5 +128,5 @@ namespace LX
std::string ToString(Token::TokenType t); std::string ToString(Token::TokenType t);
// Lexer function to take in a file and output a vector of tokens // // Lexer function to take in a file and output a vector of tokens //
const std::vector<Token> LexicalAnalyze(const std::string& contents, const std::streamsize len, std::ofstream* log); const std::vector<Token> LexicalAnalyze(const std::string& contents, const std::streamsize len);
} }

View File

@@ -51,7 +51,7 @@ namespace LX::AST
virtual llvm::Value* GenIR(InfoLLVM& LLVM) = 0; virtual llvm::Value* GenIR(InfoLLVM& LLVM) = 0;
// Function to log the node to a file // // Function to log the node to a file //
virtual void Log(std::ofstream* log, unsigned depth) = 0; virtual void Log(unsigned depth) = 0;
// Function for generating C/C++ code (Currently not implemented) // // Function for generating C/C++ code (Currently not implemented) //
//virtual void GenC() = 0; //virtual void GenC() = 0;
@@ -143,7 +143,7 @@ namespace LX
}; };
// Turns the tokens of a file into it's abstract syntax tree equivalent // // Turns the tokens of a file into it's abstract syntax tree equivalent //
FileAST TurnTokensIntoAbstractSyntaxTree(std::vector<Token>& tokens, std::ofstream* log); FileAST TurnTokensIntoAbstractSyntaxTree(std::vector<Token>& tokens);
// Turns an abstract binary tree into LLVM intermediate representation // // Turns an abstract binary tree into LLVM intermediate representation //
void GenerateIR(FileAST& ast, const std::string& name, const std::filesystem::path& IRPath); void GenerateIR(FileAST& ast, const std::string& name, const std::filesystem::path& IRPath);

View File

@@ -33,20 +33,16 @@ namespace LX
} }
} }
extern "C" int __declspec(dllexport) GenIR(const char* a_inpPath, const char* a_outPath, const char* a_logPath) extern "C" int __declspec(dllexport) GenIR(const char* a_inpPath, const char* a_outPath)
{ {
// Creates the file paths outside of the try-catch so they can be used in errors // // Creates the file paths outside of the try-catch so they can be used in errors //
std::filesystem::path inpPath; std::filesystem::path inpPath;
std::filesystem::path outPath; std::filesystem::path outPath;
std::filesystem::path logPath;
// Creates the contents string outside of the try-catch so they can be used in errors // // Creates the contents string outside of the try-catch so they can be used in errors //
std::string contents; std::string contents;
LX::Token::source = &contents; LX::Token::source = &contents;
// Creates the log-file out of the try-catch so it can be closed propely if an error is thrown //
std::unique_ptr<std::ofstream> log = nullptr;
try try
{ {
// Turns the file paths into the C++ type for handling them // // Turns the file paths into the C++ type for handling them //
@@ -69,33 +65,22 @@ extern "C" int __declspec(dllexport) GenIR(const char* a_inpPath, const char* a_
LX::ThrowIf<LX::InvalidFilePath>(outFile.is_open() == false, "output file path", outPath); LX::ThrowIf<LX::InvalidFilePath>(outFile.is_open() == false, "output file path", outPath);
outFile.close(); // Opened just to check we can outFile.close(); // Opened just to check we can
// Opens the log file (if there is one specified //
if (a_logPath != nullptr)
{
logPath = a_logPath;
log = std::make_unique<std::ofstream>(logPath);
LX::ThrowIf<LX::InvalidFilePath>(log->is_open() == false, "log file path", logPath);
}
// Prints the full paths to the console to let the user know compiling is being done // // Prints the full paths to the console to let the user know compiling is being done //
std::cout << std::filesystem::absolute(inpPath) << " -> " << std::filesystem::absolute(outPath) << std::endl; std::cout << std::filesystem::absolute(inpPath) << " -> " << std::filesystem::absolute(outPath) << std::endl;
// Create tokens out of the input file // // Create tokens out of the input file //
LX::InvalidCharInSource::s_Source = &contents; LX::InvalidCharInSource::s_Source = &contents;
LX::InvalidCharInSource::s_SourceFile = &inpPath; LX::InvalidCharInSource::s_SourceFile = &inpPath;
std::vector<LX::Token>tokens = LX::LexicalAnalyze(contents, len, log.get()); std::vector<LX::Token>tokens = LX::LexicalAnalyze(contents, len);
LX::SafeFlush(log.get());
// Turns the tokens into an AST // // Turns the tokens into an AST //
LX::UnexpectedToken::s_Source = &contents; LX::UnexpectedToken::s_Source = &contents;
LX::UnexpectedToken::s_SourceFile = &inpPath; LX::UnexpectedToken::s_SourceFile = &inpPath;
LX::FileAST AST = LX::TurnTokensIntoAbstractSyntaxTree(tokens, log.get()); LX::FileAST AST = LX::TurnTokensIntoAbstractSyntaxTree(tokens);
LX::SafeFlush(log.get());
// Turns the AST into LLVM IR // // Turns the AST into LLVM IR //
LX::GenerateIR(AST, inpPath.filename().string(), outPath); LX::GenerateIR(AST, inpPath.filename().string(), outPath);
LX::SafeFlush(log.get());
// Returns success // Returns success
return 0; return 0;
@@ -103,9 +88,8 @@ extern "C" int __declspec(dllexport) GenIR(const char* a_inpPath, const char* a_
catch(LX::RuntimeError& e) catch(LX::RuntimeError& e)
{ {
// Closes the log to save everything outputted to it after logging the error // // Logs the error. Does not need to close it as it is done after this function returns //
LX::SafeLog(log.get(), LX::LOG_BREAK, "Error thrown of type: ", e.ErrorType(), LX::LOG_BREAK); LX::Log::LogNewSection("Error thrown of type: ", e.ErrorType());
if (log != nullptr) { log->close(); }
// Logs the errors type to the console if built as Debug // // Logs the errors type to the console if built as Debug //
#ifdef _DEBUG #ifdef _DEBUG
@@ -122,8 +106,8 @@ extern "C" int __declspec(dllexport) GenIR(const char* a_inpPath, const char* a_
// Catches any std errors, there should be none // // Catches any std errors, there should be none //
catch (std::exception& e) catch (std::exception& e)
{ {
// Closes the log if it is open to get as much info as possible // // Logs the error. Does not need to close it as it is done after this function returns //
if (log != nullptr) { log->close(); } LX::Log::LogNewSection("std::exception thrown: ", e.what());
// Prints the std exception to the console // // Prints the std exception to the console //
// Any errors here are problems with the code // // Any errors here are problems with the code //
@@ -134,24 +118,9 @@ extern "C" int __declspec(dllexport) GenIR(const char* a_inpPath, const char* a_
return -1; return -1;
} }
// Catches errors that i was too lazy to code //
catch (int)
{
// Closes the log if it is open to get as much info as possible //
if (log != nullptr) { log->close(); }
std::cout << "An placeholder error occured. Maybe use a language that wasn't coded by a lazy person.\n" << std::endl;
// Exit code -1 means an undefined error //
return -1;
}
// Default catches any non-specified errors // // Default catches any non-specified errors //
catch (...) catch (...)
{ {
// Closes the log if it is open to get as much info as possible //
if (log != nullptr) { log->close(); }
// Exit code -1 means an undefined error // // Exit code -1 means an undefined error //
return -1; return -1;
} }

View File

@@ -14,7 +14,7 @@ namespace LX_Build
[LibraryImport ("Generator.dll", StringMarshalling = StringMarshalling.Custom, [LibraryImport ("Generator.dll", StringMarshalling = StringMarshalling.Custom,
StringMarshallingCustomType = typeof(System.Runtime.InteropServices.Marshalling.AnsiStringMarshaller))] StringMarshallingCustomType = typeof(System.Runtime.InteropServices.Marshalling.AnsiStringMarshaller))]
[UnmanagedCallConv(CallConvs = new Type[] { typeof(System.Runtime.CompilerServices.CallConvCdecl) })] [UnmanagedCallConv(CallConvs = new Type[] { typeof(System.Runtime.CompilerServices.CallConvCdecl) })]
public static partial int GenIR(string arg1, string arg2, string? arg3); public static partial int GenIR(string arg1, string arg2);
// Sets the directory to import the DLLs from // // Sets the directory to import the DLLs from //
public static void Init() public static void Init()

View File

@@ -45,7 +45,7 @@ namespace LX_Build
LX_API.Init(); LX_API.Init();
// Generates LLVM IR with the example files // // Generates LLVM IR with the example files //
if (LX_API.GenIR("example/main.lx", "example/main.ll", "example/log") != 0) if (LX_API.GenIR("example/main.lx", "example/main.ll") != 0)
{ {
// Quits if the IR Generation fails // // Quits if the IR Generation fails //
// The C++ script handles all of the error message outputting // // The C++ script handles all of the error message outputting //

View File

@@ -27,8 +27,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LX-Build", "LX-Build\LX-Bui
{C88042E2-0E09-4383-93F8-C79F9EE1E897} = {C88042E2-0E09-4383-93F8-C79F9EE1E897} {C88042E2-0E09-4383-93F8-C79F9EE1E897} = {C88042E2-0E09-4383-93F8-C79F9EE1E897}
EndProjectSection EndProjectSection
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{4AD62954-631A-4D0F-877E-E1C66E8CEC00}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Common", "Common\Common.vcxproj", "{0ABB03B7-E61A-4040-A512-FC05AA35B2A6}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Common", "Common\Common.vcxproj", "{0ABB03B7-E61A-4040-A512-FC05AA35B2A6}"
EndProject EndProject
Global Global
@@ -109,7 +107,6 @@ Global
{4E4019F5-12E0-4EE2-9658-A0DD3038EEDA} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} {4E4019F5-12E0-4EE2-9658-A0DD3038EEDA} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{D6EAFB31-4AFD-4989-9522-D6609AC4ED64} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} {D6EAFB31-4AFD-4989-9522-D6609AC4ED64} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{C88042E2-0E09-4383-93F8-C79F9EE1E897} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} {C88042E2-0E09-4383-93F8-C79F9EE1E897} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{0ABB03B7-E61A-4040-A512-FC05AA35B2A6} = {4AD62954-631A-4D0F-877E-E1C66E8CEC00}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {411AFEC9-4075-4FCC-B95A-9288BC822E90} SolutionGuid = {411AFEC9-4075-4FCC-B95A-9288BC822E90}

View File

@@ -175,10 +175,10 @@ namespace LX
} }
} }
const std::vector<Token> LX::LexicalAnalyze(const std::string& contents, std::streamsize len, std::ofstream* log) const std::vector<Token> LX::LexicalAnalyze(const std::string& contents, std::streamsize len)
{ {
// Logs the start of the lexical analysis // Logs the start of the lexical analysis
SafeLog(log, LOG_BREAK, "Started lexing file", LOG_BREAK); Log::LogNewSection("Lexing file");
// Allocates a large ammount of memory to hold the output // // Allocates a large ammount of memory to hold the output //
// Will shrink the size later on to stop excess memory being allocated // // Will shrink the size later on to stop excess memory being allocated //
@@ -187,7 +187,7 @@ namespace LX
// Trackers for when the program is iterating over the file // // Trackers for when the program is iterating over the file //
LexerInfo info; LexerInfo info;
// Iterates over the file and turns it into tokens // // Iterates over the file and turns it into tokens //
while (info.index < len) while (info.index < len)
{ {
@@ -344,11 +344,9 @@ namespace LX
// Log dumps A LOT of info // // Log dumps A LOT of info //
#ifdef LOG_EVERYTHING Log::out
SafeLog
( (
log, "Index: ", std::left, std::setw(3), info.index, "Index: ", std::left, std::setw(3), info.index,
" Is Alpha: ", info.isAlpha, " Is Alpha: ", info.isAlpha,
" Is Numeric: ", info.isNumeric, " Is Numeric: ", info.isNumeric,
" In Comment: ", info.inComment, " In Comment: ", info.inComment,
@@ -360,8 +358,6 @@ namespace LX
" Current: {", PrintChar(current), "}" " Current: {", PrintChar(current), "}"
); );
#endif // LOG_EVERYTHING
// Updates trackers to their default state of a new character // // Updates trackers to their default state of a new character //
info.index++; info.index++;
@@ -371,28 +367,22 @@ namespace LX
info.wasLastCharNumeric = info.isNumeric; info.wasLastCharNumeric = info.isNumeric;
} }
// Logs the tokens if logging is on // Log::out("\n"); // Puts a space to clean up the log
if (log != nullptr)
for (auto& token : tokens)
{ {
#ifdef LOG_EVERYTHING Log::out
SafeLog(log, "\n"); // Puts a space when there is a lot in the log (
#endif // LOG_EVERYTHING std::left,
"{ Line: ", std::setw(3), token.line,
for (auto& token : tokens) ", Index: ", std::setw(3), token.index,
{ ", Length: ", std::setw(2), token.length, " } ",
SafeLog std::setw(30), ToStringNoFormat(token.type) + ":", "{", token.GetContents(), "}"
( );
log, std::left,
"{ Line: ", std::setw(3), token.line,
", Index: ", std::setw(3), token.index,
", Length: ", std::setw(2), token.length, " } ",
std::setw(30), ToStringNoFormat(token.type) + ":", "{", token.GetContents(), "}"
);
}
SafeLog(log, "\n END OF TOKENS");
} }
Log::out("End of tokens");
// Shrinks the vector down to minimum size before returning to avoid excess memory being allocated // Shrinks the vector down to minimum size before returning to avoid excess memory being allocated
tokens.shrink_to_fit(); tokens.shrink_to_fit();
return tokens; return tokens;

View File

@@ -31,7 +31,7 @@ namespace LX::AST
llvm::Value* GenIR(InfoLLVM& LLVM) override; llvm::Value* GenIR(InfoLLVM& LLVM) override;
// Function to log the node to a file, will throw an error if called on this class // // Function to log the node to a file, will throw an error if called on this class //
void Log(std::ofstream* log, unsigned depth) override; void Log(unsigned depth) override;
// The nodes that are contained within this node // // The nodes that are contained within this node //
std::vector<std::unique_ptr<Node>> nodes; std::vector<std::unique_ptr<Node>> nodes;
@@ -48,7 +48,7 @@ namespace LX::AST
llvm::Value* GenIR(InfoLLVM& LLVM) override; llvm::Value* GenIR(InfoLLVM& LLVM) override;
// Function to log the node to a file // // Function to log the node to a file //
void Log(std::ofstream* log, unsigned depth) override; void Log(unsigned depth) override;
private: private:
// The number it stores // // The number it stores //
@@ -67,7 +67,7 @@ namespace LX::AST
llvm::Value* GenIR(InfoLLVM& LLVM) override; llvm::Value* GenIR(InfoLLVM& LLVM) override;
// Function to log the node to a file // // Function to log the node to a file //
void Log(std::ofstream* log, unsigned depth) override; void Log(unsigned depth) override;
private: private:
// The sides of the operation // // The sides of the operation //
@@ -89,7 +89,7 @@ namespace LX::AST
llvm::Value* GenIR(InfoLLVM& LLVM) override; llvm::Value* GenIR(InfoLLVM& LLVM) override;
// Function to log the node to a file // // Function to log the node to a file //
void Log(std::ofstream* log, unsigned depth) override; void Log(unsigned depth) override;
private: private:
// What it is returning (can be null) // // What it is returning (can be null) //
@@ -107,7 +107,7 @@ namespace LX::AST
llvm::Value* GenIR(InfoLLVM& LLVM) override; llvm::Value* GenIR(InfoLLVM& LLVM) override;
// Function to log the node to a file // // Function to log the node to a file //
void Log(std::ofstream* log, unsigned depth) override; void Log(unsigned depth) override;
private: private:
// Name of the variable // // Name of the variable //
@@ -127,7 +127,7 @@ namespace LX::AST
llvm::Value* GenIR(InfoLLVM& LLVM) override; llvm::Value* GenIR(InfoLLVM& LLVM) override;
// Function to log the node to a file // // Function to log the node to a file //
void Log(std::ofstream* log, unsigned depth) override; void Log(unsigned depth) override;
private: private:
// Name of the variable // // Name of the variable //
@@ -148,7 +148,7 @@ namespace LX::AST
llvm::Value* GenIR(InfoLLVM& LLVM) override; llvm::Value* GenIR(InfoLLVM& LLVM) override;
// Function to log the node to a file // // Function to log the node to a file //
void Log(std::ofstream* log, unsigned depth) override; void Log(unsigned depth) override;
private: private:
// The name of the variable // // The name of the variable //

View File

@@ -4,61 +4,59 @@
namespace LX::AST namespace LX::AST
{ {
void MultiNode::Log(std::ofstream* log, unsigned depth) void MultiNode::Log(unsigned depth)
{ {
throw int(); // <- TODO: Make an error for this throw int(); // <- TODO: Make an error for this
} }
void NumberLiteral::Log(std::ofstream* log, unsigned depth) void NumberLiteral::Log(unsigned depth)
{ {
(*log) << std::string(depth, '\t'); Log::out(std::string(depth, '\t'), "Number: ", m_Number);
(*log) << "Number: " << m_Number << "\n";
} }
void Operation::Log(std::ofstream* log, unsigned depth) void Operation::Log(unsigned depth)
{ {
(*log) << std::string(depth, '\t'); Log::out(std::string(depth, '\t'), "Operation {", ToString(m_Operand), "}:");
(*log) << "Operation {" << ToString(m_Operand) << "}:\n";
(*log) << std::string(depth + 1, '\t') << "LHS:\n"; Log::out(std::string(depth + 1, '\t'), "LHS:");
m_Lhs.get()->Log(log, depth + 2); m_Lhs->Log(depth + 2);
(*log) << std::string(depth + 1, '\t') << "RHS:\n";
m_Rhs.get()->Log(log, depth + 2); Log::out(std::string(depth + 1, '\t'), "RHS:");
m_Rhs->Log(depth + 2);
} }
void ReturnStatement::Log(std::ofstream* log, unsigned depth) void ReturnStatement::Log(unsigned depth)
{ {
(*log) << std::string(depth, '\t'); Log::out<Log::Format::NONE>(std::string(depth, '\t'), "Return");
if (m_Val == nullptr) if (m_Val != nullptr)
{ {
(*log) << "Return\n"; Log::out(':');
m_Val->Log(depth + 1);
} }
else else
{ {
(*log) << "Return:\n"; Log::out<Log::Format::NONE>('\n');
m_Val->Log(log, depth + 1);
} }
} }
void VariableDeclaration::Log(std::ofstream* log, unsigned depth) void VariableDeclaration::Log(unsigned depth)
{ {
(*log) << std::string(depth, '\t'); Log::out(std::string(depth, '\t'), "Variable declaration: ", m_Name);
(*log) << "Variable declaration: " << m_Name << "\n";
} }
void VariableAssignment::Log(std::ofstream* log, unsigned depth) void VariableAssignment::Log(unsigned depth)
{ {
(*log) << std::string(depth, '\t'); Log::out(std::string(depth, '\t'), "Variable assignment:");
(*log) << "Variable assignment:\n";
(*log) << std::string(depth + 1, '\t') << "To: " << m_Name << "\n"; Log::out(std::string(depth + 1, '\t'), "To: ", m_Name);
(*log) << std::string(depth + 1, '\t') << "Value:\n"; Log::out(std::string(depth + 1, '\t'), "Value:");
m_Value.get()->Log(log, depth + 2); m_Value->Log(depth + 2);
} }
void VariableAccess::Log(std::ofstream* log, unsigned depth) void VariableAccess::Log(unsigned depth)
{ {
(*log) << std::string(depth, '\t'); Log::out(std::string(depth, '\t'), "Variable: ", m_Name);
(*log) << "Variable: " << m_Name << '\n';
} }
} }

View File

@@ -29,16 +29,13 @@ namespace LX
struct Parser struct Parser
{ {
// Passes constructor args to members // // Passes constructor args to members //
Parser(std::vector<Token>& _tokens, std::ofstream* _log) Parser(std::vector<Token>& _tokens)
: tokens(_tokens), log(_log), index(0), len(_tokens.size()), scopeDepth(0) : tokens(_tokens), index(0), len(_tokens.size()), scopeDepth(0)
{} {}
// Tokens created by the lexer // // Tokens created by the lexer //
std::vector<Token>& tokens; std::vector<Token>& tokens;
// Log to output to (can be null) //
std::ofstream* log;
// Length of the the token vector // // Length of the the token vector //
const size_t len; const size_t len;
@@ -203,14 +200,14 @@ namespace LX
} }
// Turns the tokens of a file into it's abstract syntax tree equivalent // // Turns the tokens of a file into it's abstract syntax tree equivalent //
FileAST TurnTokensIntoAbstractSyntaxTree(std::vector<Token>& tokens, std::ofstream* log) FileAST TurnTokensIntoAbstractSyntaxTree(std::vector<Token>& tokens)
{ {
// Logs the start of the parsing // Logs the start of the parsing
SafeLog(log, LOG_BREAK, "Started parsing tokens", LOG_BREAK); Log::LogNewSection("Started parsing tokens");
// Creates the output storer and the parser // // Creates the output storer and the parser //
FileAST output; FileAST output;
Parser p(tokens, log); Parser p(tokens);
// Loops over the tokens and calls the correct parsing function // // Loops over the tokens and calls the correct parsing function //
// Which depends on their type and current state of the parser // // Which depends on their type and current state of the parser //
@@ -261,7 +258,7 @@ namespace LX
for (std::unique_ptr<AST::Node>& containedNode : ((AST::MultiNode*)node.get())->nodes) for (std::unique_ptr<AST::Node>& containedNode : ((AST::MultiNode*)node.get())->nodes)
{ {
// Logs the node to the log // // Logs the node to the log //
if (log != nullptr) { node->Log(log, 0); } node->Log(0);
// Adds it to the vector // // Adds it to the vector //
func.body.push_back(std::move(containedNode)); func.body.push_back(std::move(containedNode));
@@ -272,7 +269,7 @@ namespace LX
else else
{ {
// Logs the node to the log // // Logs the node to the log //
if (log != nullptr) { node->Log(log, 0); } node->Log(0);
// Adds it to the vector // // Adds it to the vector //
func.body.push_back(std::move(node)); func.body.push_back(std::move(node));
@@ -296,7 +293,7 @@ namespace LX
// Logs that AST has finished parsing // // Logs that AST has finished parsing //
// TODO: Make this output the AST in a human-readable form // // TODO: Make this output the AST in a human-readable form //
SafeLog(log, "AST length: ", output.functions[0].body.size()); Log::out("AST length: ", output.functions[0].body.size());
// Returns the output and shrinks all uneccesarry allocated memory // Returns the output and shrinks all uneccesarry allocated memory
output.functions.shrink_to_fit(); output.functions.shrink_to_fit();

View File

@@ -13,12 +13,10 @@ This is my custom compiled language written in C++ based off of the LLVM toolcha
- Errors - Errors
- All simple errors (no members) use the same type - All simple errors (no members) use the same type
- Logging - Logging
- Less templates - Choose what is logged (if any)
- Standard for formatting
- Choose what is logged
- Refactor - Refactor
- Use dynamic linking for debug builds (faster build times) - Parser needs folders
- General clean up - Better .h files
### Stuff I want to do later (unordered) ### Stuff I want to do later (unordered)
- I/O manager (Console, Files) - I/O manager (Console, Files)

Binary file not shown.

Binary file not shown.