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" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\Console.cpp" />
<ClCompile Include="src\dllmain.cpp" />
<ClCompile Include="src\Logger.cpp" />
<ClCompile Include="src\pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>

View File

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

View File

@@ -11,7 +11,8 @@
#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#undef NOMINMAX
#undef WIN32_LEAN_AND_MEAN
// Else alerts the user that their system is not supported //
#else
#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"
#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 //
#include <unordered_map>

View File

@@ -1,41 +1,30 @@
namespace LX
{
// Enum of colors with their Win32 equivalent value //
enum class Color
{
BLACK = 0,
BLUE = 1,
GREEN = 2,
AQUA = 3,
RED = 4,
PURPLE = 5,
YELLOW = 6,
LIGHT_GRAY = 7,
LIGHT_BLUE = 9,
LIGHT_GREEN = 10,
LIGHT_AQUA = 11,
LIGHT_RED = 12,
LIGHT_PURPLE = 13,
LIGHT_YELLOW = 14,
WHITE = 15
BLACK = 0,
BLUE = 1,
GREEN = 2,
AQUA = 3,
RED = 4,
PURPLE = 5,
YELLOW = 6,
LIGHT_GRAY = 7,
LIGHT_BLUE = 9,
LIGHT_GREEN = 10,
LIGHT_AQUA = 11,
LIGHT_RED = 12,
LIGHT_PURPLE = 13,
LIGHT_YELLOW = 14,
WHITE = 15
};
inline 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);
}
// 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);
// 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 //
size_t start = src.rfind('\n', index);

View File

@@ -1,23 +1,51 @@
namespace LX
{
template<typename... Args>
inline void SafeLog(std::ofstream* log, Args... args)
class COMMON_API Log
{
if (log != nullptr)
{
(*log << ... << args);
(*log << '\n');
}
}
public:
// This class should never be constructed //
Log() = delete;
inline void SafeFlush(std::ofstream* log)
{
if (log != nullptr)
{
log->flush();
}
}
enum class Format
{
AUTO,
NONE
};
// Gives a standard way to mark a change between different sections within the log output //
constexpr const char* LOG_BREAK = "\n-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n";
template<Format format = Format::AUTO, typename... Args>
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
{
// All the different functions that can be called by the system //
// Currently all empty but here for easier future development //
using DllFunc = bool(HMODULE);
static bool ProcAttach(HMODULE hModule)
{
Log::Init(); // Initalises the log before the main process starts
return true;
}
static bool ProcDetach(HMODULE hModule)
{
return true;
}
static bool ThreadAttach(HMODULE hModule)
{
}
static bool ThreadDetach(HMODULE hModule)
{
}
static bool ThreadAttach(HMODULE hModule) { return true; }
static bool ThreadDetach(HMODULE hModule) { return true; }
}
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:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
{ DLL_PROCESS_ATTACH, LX::ProcAttach },
{ DLL_PROCESS_DETACH, LX::ProcDetach },
{ DLL_THREAD_ATTACH , LX::ThreadAttach },
{ DLL_THREAD_DETACH , LX::ThreadDetach }
};
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>
<GenerateDebugInformation>true</GenerateDebugInformation>
<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>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@@ -144,7 +144,7 @@
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<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>
</ItemDefinitionGroup>
<ItemGroup>
@@ -158,6 +158,11 @@
<ClInclude Include="inc\Lexer.h" />
<ClInclude Include="inc\Parser.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Common\Common.vcxproj">
<Project>{0abb03b7-e61a-4040-a512-fc05aa35b2a6}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>

View File

@@ -128,5 +128,5 @@ namespace LX
std::string ToString(Token::TokenType t);
// 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;
// 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) //
//virtual void GenC() = 0;
@@ -143,7 +143,7 @@ namespace LX
};
// 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 //
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 //
std::filesystem::path inpPath;
std::filesystem::path outPath;
std::filesystem::path logPath;
// Creates the contents string outside of the try-catch so they can be used in errors //
std::string 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
{
// 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);
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 //
std::cout << std::filesystem::absolute(inpPath) << " -> " << std::filesystem::absolute(outPath) << std::endl;
// Create tokens out of the input file //
LX::InvalidCharInSource::s_Source = &contents;
LX::InvalidCharInSource::s_SourceFile = &inpPath;
std::vector<LX::Token>tokens = LX::LexicalAnalyze(contents, len, log.get());
LX::SafeFlush(log.get());
std::vector<LX::Token>tokens = LX::LexicalAnalyze(contents, len);
// Turns the tokens into an AST //
LX::UnexpectedToken::s_Source = &contents;
LX::UnexpectedToken::s_SourceFile = &inpPath;
LX::FileAST AST = LX::TurnTokensIntoAbstractSyntaxTree(tokens, log.get());
LX::SafeFlush(log.get());
LX::FileAST AST = LX::TurnTokensIntoAbstractSyntaxTree(tokens);
// Turns the AST into LLVM IR //
LX::GenerateIR(AST, inpPath.filename().string(), outPath);
LX::SafeFlush(log.get());
// Returns success
return 0;
@@ -103,9 +88,8 @@ extern "C" int __declspec(dllexport) GenIR(const char* a_inpPath, const char* a_
catch(LX::RuntimeError& e)
{
// Closes the log to save everything outputted to it after logging the error //
LX::SafeLog(log.get(), LX::LOG_BREAK, "Error thrown of type: ", e.ErrorType(), LX::LOG_BREAK);
if (log != nullptr) { log->close(); }
// Logs the error. Does not need to close it as it is done after this function returns //
LX::Log::LogNewSection("Error thrown of type: ", e.ErrorType());
// Logs the errors type to the console if built as 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 //
catch (std::exception& e)
{
// Closes the log if it is open to get as much info as possible //
if (log != nullptr) { log->close(); }
// Logs the error. Does not need to close it as it is done after this function returns //
LX::Log::LogNewSection("std::exception thrown: ", e.what());
// Prints the std exception to the console //
// 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;
}
// 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 //
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 //
return -1;
}

View File

@@ -14,7 +14,7 @@ namespace LX_Build
[LibraryImport ("Generator.dll", StringMarshalling = StringMarshalling.Custom,
StringMarshallingCustomType = typeof(System.Runtime.InteropServices.Marshalling.AnsiStringMarshaller))]
[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 //
public static void Init()

View File

@@ -45,7 +45,7 @@ namespace LX_Build
LX_API.Init();
// 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 //
// 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}
EndProjectSection
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}"
EndProject
Global
@@ -109,7 +107,6 @@ Global
{4E4019F5-12E0-4EE2-9658-A0DD3038EEDA} = {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}
{0ABB03B7-E61A-4040-A512-FC05AA35B2A6} = {4AD62954-631A-4D0F-877E-E1C66E8CEC00}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
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
SafeLog(log, LOG_BREAK, "Started lexing file", LOG_BREAK);
Log::LogNewSection("Lexing file");
// Allocates a large ammount of memory to hold the output //
// Will shrink the size later on to stop excess memory being allocated //
@@ -344,11 +344,9 @@ namespace LX
// Log dumps A LOT of info //
#ifdef LOG_EVERYTHING
SafeLog
Log::out
(
log, "Index: ", std::left, std::setw(3), info.index,
"Index: ", std::left, std::setw(3), info.index,
" Is Alpha: ", info.isAlpha,
" Is Numeric: ", info.isNumeric,
" In Comment: ", info.inComment,
@@ -360,8 +358,6 @@ namespace LX
" Current: {", PrintChar(current), "}"
);
#endif // LOG_EVERYTHING
// Updates trackers to their default state of a new character //
info.index++;
@@ -371,28 +367,22 @@ namespace LX
info.wasLastCharNumeric = info.isNumeric;
}
// Logs the tokens if logging is on //
if (log != nullptr)
Log::out("\n"); // Puts a space to clean up the log
for (auto& token : tokens)
{
#ifdef LOG_EVERYTHING
SafeLog(log, "\n"); // Puts a space when there is a lot in the log
#endif // LOG_EVERYTHING
for (auto& token : tokens)
{
SafeLog
(
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
(
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(), "}"
);
}
Log::out("End of tokens");
// Shrinks the vector down to minimum size before returning to avoid excess memory being allocated
tokens.shrink_to_fit();
return tokens;

View File

@@ -31,7 +31,7 @@ namespace LX::AST
llvm::Value* GenIR(InfoLLVM& LLVM) override;
// 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 //
std::vector<std::unique_ptr<Node>> nodes;
@@ -48,7 +48,7 @@ namespace LX::AST
llvm::Value* GenIR(InfoLLVM& LLVM) override;
// Function to log the node to a file //
void Log(std::ofstream* log, unsigned depth) override;
void Log(unsigned depth) override;
private:
// The number it stores //
@@ -67,7 +67,7 @@ namespace LX::AST
llvm::Value* GenIR(InfoLLVM& LLVM) override;
// Function to log the node to a file //
void Log(std::ofstream* log, unsigned depth) override;
void Log(unsigned depth) override;
private:
// The sides of the operation //
@@ -89,7 +89,7 @@ namespace LX::AST
llvm::Value* GenIR(InfoLLVM& LLVM) override;
// Function to log the node to a file //
void Log(std::ofstream* log, unsigned depth) override;
void Log(unsigned depth) override;
private:
// What it is returning (can be null) //
@@ -107,7 +107,7 @@ namespace LX::AST
llvm::Value* GenIR(InfoLLVM& LLVM) override;
// Function to log the node to a file //
void Log(std::ofstream* log, unsigned depth) override;
void Log(unsigned depth) override;
private:
// Name of the variable //
@@ -127,7 +127,7 @@ namespace LX::AST
llvm::Value* GenIR(InfoLLVM& LLVM) override;
// Function to log the node to a file //
void Log(std::ofstream* log, unsigned depth) override;
void Log(unsigned depth) override;
private:
// Name of the variable //
@@ -148,7 +148,7 @@ namespace LX::AST
llvm::Value* GenIR(InfoLLVM& LLVM) override;
// Function to log the node to a file //
void Log(std::ofstream* log, unsigned depth) override;
void Log(unsigned depth) override;
private:
// The name of the variable //

View File

@@ -4,61 +4,59 @@
namespace LX::AST
{
void MultiNode::Log(std::ofstream* log, unsigned depth)
void MultiNode::Log(unsigned depth)
{
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) << "Number: " << m_Number << "\n";
Log::out(std::string(depth, '\t'), "Number: ", m_Number);
}
void Operation::Log(std::ofstream* log, unsigned depth)
void Operation::Log(unsigned depth)
{
(*log) << std::string(depth, '\t');
(*log) << "Operation {" << ToString(m_Operand) << "}:\n";
(*log) << std::string(depth + 1, '\t') << "LHS:\n";
m_Lhs.get()->Log(log, depth + 2);
(*log) << std::string(depth + 1, '\t') << "RHS:\n";
m_Rhs.get()->Log(log, depth + 2);
Log::out(std::string(depth, '\t'), "Operation {", ToString(m_Operand), "}:");
Log::out(std::string(depth + 1, '\t'), "LHS:");
m_Lhs->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
{
(*log) << "Return:\n";
m_Val->Log(log, depth + 1);
Log::out<Log::Format::NONE>('\n');
}
}
void VariableDeclaration::Log(std::ofstream* log, unsigned depth)
void VariableDeclaration::Log(unsigned depth)
{
(*log) << std::string(depth, '\t');
(*log) << "Variable declaration: " << m_Name << "\n";
Log::out(std::string(depth, '\t'), "Variable declaration: ", m_Name);
}
void VariableAssignment::Log(std::ofstream* log, unsigned depth)
void VariableAssignment::Log(unsigned depth)
{
(*log) << std::string(depth, '\t');
(*log) << "Variable assignment:\n";
(*log) << std::string(depth + 1, '\t') << "To: " << m_Name << "\n";
(*log) << std::string(depth + 1, '\t') << "Value:\n";
m_Value.get()->Log(log, depth + 2);
Log::out(std::string(depth, '\t'), "Variable assignment:");
Log::out(std::string(depth + 1, '\t'), "To: ", m_Name);
Log::out(std::string(depth + 1, '\t'), "Value:");
m_Value->Log(depth + 2);
}
void VariableAccess::Log(std::ofstream* log, unsigned depth)
void VariableAccess::Log(unsigned depth)
{
(*log) << std::string(depth, '\t');
(*log) << "Variable: " << m_Name << '\n';
Log::out(std::string(depth, '\t'), "Variable: ", m_Name);
}
}

View File

@@ -29,16 +29,13 @@ namespace LX
struct Parser
{
// Passes constructor args to members //
Parser(std::vector<Token>& _tokens, std::ofstream* _log)
: tokens(_tokens), log(_log), index(0), len(_tokens.size()), scopeDepth(0)
Parser(std::vector<Token>& _tokens)
: tokens(_tokens), index(0), len(_tokens.size()), scopeDepth(0)
{}
// Tokens created by the lexer //
std::vector<Token>& tokens;
// Log to output to (can be null) //
std::ofstream* log;
// Length of the the token vector //
const size_t len;
@@ -203,14 +200,14 @@ namespace LX
}
// 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
SafeLog(log, LOG_BREAK, "Started parsing tokens", LOG_BREAK);
Log::LogNewSection("Started parsing tokens");
// Creates the output storer and the parser //
FileAST output;
Parser p(tokens, log);
Parser p(tokens);
// Loops over the tokens and calls the correct parsing function //
// 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)
{
// Logs the node to the log //
if (log != nullptr) { node->Log(log, 0); }
node->Log(0);
// Adds it to the vector //
func.body.push_back(std::move(containedNode));
@@ -272,7 +269,7 @@ namespace LX
else
{
// Logs the node to the log //
if (log != nullptr) { node->Log(log, 0); }
node->Log(0);
// Adds it to the vector //
func.body.push_back(std::move(node));
@@ -296,7 +293,7 @@ namespace LX
// Logs that AST has finished parsing //
// 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
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
- All simple errors (no members) use the same type
- Logging
- Less templates
- Standard for formatting
- Choose what is logged
- Choose what is logged (if any)
- Refactor
- Use dynamic linking for debug builds (faster build times)
- General clean up
- Parser needs folders
- Better .h files
### Stuff I want to do later (unordered)
- I/O manager (Console, Files)

Binary file not shown.

Binary file not shown.