mirror of
https://github.com/PashaBibko/LX.git
synced 2026-04-03 17:39:02 +00:00
Changed how scopes work
Also added logging and GenIR functions for VariableDeclaration
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
// Lexer foward declares fstream components so we can use them here //
|
// Lexer foward declares fstream components so we can use them here //
|
||||||
#include <Lexer.h>
|
#include <Lexer.h>
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_set>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
// Foward declares STD stuff that is passed around //
|
// Foward declares STD stuff that is passed around //
|
||||||
@@ -30,6 +30,7 @@ namespace LX::AST
|
|||||||
|
|
||||||
NUMBER_LITERAL,
|
NUMBER_LITERAL,
|
||||||
OPERATION,
|
OPERATION,
|
||||||
|
VARIABLE_DECLARATION,
|
||||||
|
|
||||||
// Control flow Nodes //
|
// Control flow Nodes //
|
||||||
|
|
||||||
@@ -81,18 +82,6 @@ namespace LX
|
|||||||
class Scope
|
class Scope
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// Struct to store all the info of a variable (excluding name as that is stored in the map) //
|
|
||||||
struct __declspec(novtable) Variable final
|
|
||||||
{
|
|
||||||
// Default constructor //
|
|
||||||
Variable() {}
|
|
||||||
|
|
||||||
// Will hold the type as part of the type here //
|
|
||||||
|
|
||||||
// The value of the variable //
|
|
||||||
llvm::Value* val = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Error thrown if the user tried to create a variable that already existed //
|
// Error thrown if the user tried to create a variable that already existed //
|
||||||
struct __declspec(novtable) VariableAlreadyExists final {};
|
struct __declspec(novtable) VariableAlreadyExists final {};
|
||||||
|
|
||||||
@@ -105,17 +94,14 @@ namespace LX
|
|||||||
{}
|
{}
|
||||||
|
|
||||||
// Gets a variable from the scope by it's name //
|
// Gets a variable from the scope by it's name //
|
||||||
Variable* GetVarOfName(const std::string& name);
|
bool DoesVarExist(const std::string& name);
|
||||||
|
|
||||||
// Creates a variable of the given name, returns nullptr if a variable with that name already exists //
|
// Creates a variable of the given name //
|
||||||
Variable* CreateVar(const std::string& name);
|
void CreateVar(const std::string& name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Base logic for getting a variable by it's name without any error checking //
|
|
||||||
Variable* GetVarOfNameImpl(const std::string& name);
|
|
||||||
|
|
||||||
// Holds all the variables in the scope (excluding ones owned by the children //
|
// Holds all the variables in the scope (excluding ones owned by the children //
|
||||||
std::unordered_map<std::string, Variable> m_LocalVariables;
|
std::unordered_set<std::string> m_LocalVariables;
|
||||||
|
|
||||||
// Holds a section of the scope, for example the variables created in a while loop //
|
// Holds a section of the scope, for example the variables created in a while loop //
|
||||||
std::unique_ptr<Scope> m_Child;
|
std::unique_ptr<Scope> m_Child;
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ namespace LX
|
|||||||
llvm::LLVMContext context;
|
llvm::LLVMContext context;
|
||||||
llvm::Module module;
|
llvm::Module module;
|
||||||
llvm::IRBuilder<> builder;
|
llvm::IRBuilder<> builder;
|
||||||
|
|
||||||
|
// Not LLVM I just cba to add this parameter to the functions that needed it //
|
||||||
|
Scope* scope;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ namespace LX
|
|||||||
{
|
{
|
||||||
// Default constructor that just initalises LLVM variables that it holds //
|
// Default constructor that just initalises LLVM variables that it holds //
|
||||||
InfoLLVM::InfoLLVM(std::string name)
|
InfoLLVM::InfoLLVM(std::string name)
|
||||||
: context{}, builder(context), module(name, context)
|
: context{}, builder(context), module(name, context), scope(nullptr)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
// Reserves space for nodes (stops excess allocations) //
|
// Reserves space for nodes (stops excess allocations) //
|
||||||
@@ -41,4 +41,9 @@ namespace LX::AST
|
|||||||
ReturnStatement::ReturnStatement(std::unique_ptr<Node> val)
|
ReturnStatement::ReturnStatement(std::unique_ptr<Node> val)
|
||||||
: Node(Node::RETURN_STATEMENT), m_Val(std::move(val))
|
: Node(Node::RETURN_STATEMENT), m_Val(std::move(val))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
// Passes constructor args to values and sets type //
|
||||||
|
VariableDeclaration::VariableDeclaration(const std::string& name)
|
||||||
|
: Node(Node::VARIABLE_DECLARATION), m_Name(name)
|
||||||
|
{}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,5 +70,10 @@ namespace LX::AST
|
|||||||
// Function for generating LLVN IR (Intermediate representation) //
|
// Function for generating LLVN IR (Intermediate representation) //
|
||||||
llvm::Value* VariableDeclaration::GenIR(InfoLLVM& LLVM)
|
llvm::Value* VariableDeclaration::GenIR(InfoLLVM& LLVM)
|
||||||
{
|
{
|
||||||
|
// Creates the variable within the scope //
|
||||||
|
LLVM.scope->CreateVar(m_Name);
|
||||||
|
|
||||||
|
// Creates the declaration within the IR //
|
||||||
|
return LLVM.builder.CreateAlloca(LLVM.builder.getInt32Ty(), nullptr, m_Name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,4 +40,10 @@ namespace LX::AST
|
|||||||
m_Val->Log(log, depth + 1);
|
m_Val->Log(log, depth + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VariableDeclaration::Log(std::ofstream* log, unsigned depth)
|
||||||
|
{
|
||||||
|
(*log) << std::string(depth, '\t');
|
||||||
|
(*log) << "Variable declaration: " << m_Name << "\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ namespace LX
|
|||||||
// Loops over the functions to generate their LLVM IR //
|
// Loops over the functions to generate their LLVM IR //
|
||||||
for (auto& func : ast.functions)
|
for (auto& func : ast.functions)
|
||||||
{
|
{
|
||||||
|
LLVM.scope = &func.scope; // Sets the current scope for the builder
|
||||||
GenerateFunctionIR(func, LLVM);
|
GenerateFunctionIR(func, LLVM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,64 +4,32 @@
|
|||||||
|
|
||||||
namespace LX
|
namespace LX
|
||||||
{
|
{
|
||||||
// Util function for getting a pointer to an item from a map //
|
bool Scope::DoesVarExist(const std::string& name)
|
||||||
static inline Scope::Variable* GetFromMap(const std::string& name, std::unordered_map<std::string, Scope::Variable>& map)
|
|
||||||
{
|
{
|
||||||
// Checks if it is in a map and if so returns it //
|
// Stores a pointer to the current scope //
|
||||||
if (auto it = map.find(name); it != map.end()) { return &it->second; }
|
|
||||||
|
|
||||||
// Else returns null //
|
|
||||||
else { return nullptr; }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Base logic for getting a variable by it's name without any error checking //
|
|
||||||
Scope::Variable* Scope::GetVarOfNameImpl(const std::string& name)
|
|
||||||
{
|
|
||||||
// Stores the current scope that is being checked for the variable //
|
|
||||||
Scope* current = this;
|
Scope* current = this;
|
||||||
|
|
||||||
// Loops over the scope and it's child to find the variable //
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
// Gets the variable (if it exists) //
|
// Checks if the variable exists in the current scope //
|
||||||
Variable* var = GetFromMap(name, current->m_LocalVariables);
|
bool exists = current->m_LocalVariables.contains(name);
|
||||||
|
if (exists) { return true; }
|
||||||
|
|
||||||
// Returns the variable if it exists //
|
// Travels to the next scope //
|
||||||
if (var != nullptr) { return var; }
|
|
||||||
|
|
||||||
// Assigns current to the child to recursively check //
|
|
||||||
// Doing it like this avoids recursive functions //
|
|
||||||
current = current->m_Child.get();
|
current = current->m_Child.get();
|
||||||
|
|
||||||
} while (current != nullptr);
|
} while (current != nullptr);
|
||||||
|
|
||||||
// Else returns a nullptr and lets the caller handle the error checking //
|
// If it gets here it means it couldnt find the variable so it doesnt exist in the current context //
|
||||||
return nullptr;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets a variable from the scope by it's name //
|
void Scope::CreateVar(const std::string& name)
|
||||||
Scope::Variable* Scope::GetVarOfName(const std::string& name)
|
|
||||||
{
|
{
|
||||||
// Gets the variable (if it exists) //
|
// Checks variable of the same name doesn't exist //
|
||||||
Variable* var = GetVarOfNameImpl(name);
|
ThrowIf<Scope::VariableAlreadyExists>(DoesVarExist(name));
|
||||||
|
|
||||||
// Throws an error if the variable doesn't exist //
|
// Else inserts it into the local set //
|
||||||
ThrowIf<VariableDoesntExist>(var == nullptr);
|
m_LocalVariables.insert(name);
|
||||||
|
|
||||||
// Else it can return the variable //
|
|
||||||
return var;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creates a variable of the given name, returns nullptr if a variable with that name already exists //
|
|
||||||
Scope::Variable* Scope::CreateVar(const std::string& name)
|
|
||||||
{
|
|
||||||
// Checks if a variable with the same name already exists //
|
|
||||||
Variable* alreadyExist = GetVarOfNameImpl(name);
|
|
||||||
|
|
||||||
// Throws an error if the variable already exists //
|
|
||||||
ThrowIf<VariableAlreadyExists>(alreadyExist != nullptr);
|
|
||||||
|
|
||||||
// Else creates the variable and returns it //
|
|
||||||
return &m_LocalVariables[name];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
func main()
|
func main()
|
||||||
{
|
{
|
||||||
int a = 5
|
int a
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user