mirror of
https://github.com/PashaBibko/LX.git
synced 2026-04-04 01:49:05 +00:00
Added scope class
This commit is contained in:
@@ -75,6 +75,10 @@ namespace LX
|
|||||||
IDENTIFIER,
|
IDENTIFIER,
|
||||||
RETURN,
|
RETURN,
|
||||||
|
|
||||||
|
// Built-in types //
|
||||||
|
|
||||||
|
INT_DEC,
|
||||||
|
|
||||||
// Symbols //
|
// Symbols //
|
||||||
|
|
||||||
OPEN_BRACKET, CLOSE_BRACKET,
|
OPEN_BRACKET, CLOSE_BRACKET,
|
||||||
@@ -83,6 +87,10 @@ namespace LX
|
|||||||
|
|
||||||
COMMA,
|
COMMA,
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
ASSIGN,
|
||||||
|
|
||||||
// Operators //
|
// Operators //
|
||||||
|
|
||||||
ADD, SUB, MUL, DIV,
|
ADD, SUB, MUL, DIV,
|
||||||
|
|||||||
@@ -3,6 +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 <memory>
|
#include <memory>
|
||||||
|
|
||||||
// Foward declares STD stuff that is passed around //
|
// Foward declares STD stuff that is passed around //
|
||||||
@@ -77,8 +78,51 @@ namespace LX
|
|||||||
Token got;
|
Token got;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Scope
|
||||||
|
{
|
||||||
|
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 //
|
||||||
|
struct __declspec(novtable) VariableAlreadyExists final {};
|
||||||
|
|
||||||
|
// Error thrown if user tries to access variable that does not exist //
|
||||||
|
struct __declspec(novtable) VariableDoesntExist final {};
|
||||||
|
|
||||||
|
// Default constructor //
|
||||||
|
Scope()
|
||||||
|
: m_LocalVariables{}, m_Child(nullptr)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Gets a variable from the scope by it's name //
|
||||||
|
Variable* GetVarOfName(const std::string& name);
|
||||||
|
|
||||||
|
// Creates a variable of the given name, returns nullptr if a variable with that name already exists //
|
||||||
|
Variable* CreateVar(const std::string& name);
|
||||||
|
|
||||||
|
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 //
|
||||||
|
std::unordered_map<std::string, Variable> m_LocalVariables;
|
||||||
|
|
||||||
|
// Holds a section of the scope, for example the variables created in a while loop //
|
||||||
|
std::unique_ptr<Scope> m_Child;
|
||||||
|
};
|
||||||
|
|
||||||
// Holds all needed info about a function //
|
// Holds all needed info about a function //
|
||||||
// Currently only holds the body but in the future will hold: name, params, namespace/class-member
|
// Currently only holds the body but in the future will hold: params, namespace/class-member //
|
||||||
struct FunctionDefinition
|
struct FunctionDefinition
|
||||||
{
|
{
|
||||||
// Defualt constructor (none other given) //
|
// Defualt constructor (none other given) //
|
||||||
@@ -87,6 +131,9 @@ namespace LX
|
|||||||
// The name of the function //
|
// The name of the function //
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
|
// The scope off the function //
|
||||||
|
Scope scope;
|
||||||
|
|
||||||
// The instructions of the body of the function //
|
// The instructions of the body of the function //
|
||||||
std::vector<std::unique_ptr<AST::Node>> body;
|
std::vector<std::unique_ptr<AST::Node>> body;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ int main(int argc, char** argv)
|
|||||||
LX::PrintStringAsColor(std::string(1, e.invalid), LX::Color::LIGHT_RED);
|
LX::PrintStringAsColor(std::string(1, e.invalid), LX::Color::LIGHT_RED);
|
||||||
std::cout << "}:\n";
|
std::cout << "}:\n";
|
||||||
std::cout << "Line: " << std::setw(lineNumberWidthInConsole) << e.line << " | " << line << "\n";
|
std::cout << "Line: " << std::setw(lineNumberWidthInConsole) << e.line << " | " << line << "\n";
|
||||||
std::cout << " " << std::setw(lineNumberWidthInConsole) << "" << " | " << std::setw(e.col + 1);
|
std::cout << " " << std::setw(lineNumberWidthInConsole) << "" << " | " << std::setw(e.col - 1) << "";
|
||||||
LX::PrintStringAsColor("^", LX::Color::LIGHT_RED);
|
LX::PrintStringAsColor("^", LX::Color::LIGHT_RED);
|
||||||
std::cout << "\n";
|
std::cout << "\n";
|
||||||
|
|
||||||
@@ -217,7 +217,7 @@ int main(int argc, char** argv)
|
|||||||
// Prints the code with the error to the console //
|
// Prints the code with the error to the console //
|
||||||
std::string errorSquiggle(e.got.length, '~');
|
std::string errorSquiggle(e.got.length, '~');
|
||||||
std::cout << "Line: " << std::setw(lineNumberWidthInConsole) << e.got.line << " | " << line << "\n";
|
std::cout << "Line: " << std::setw(lineNumberWidthInConsole) << e.got.line << " | " << line << "\n";
|
||||||
std::cout << " " << std::setw(lineNumberWidthInConsole) << "" << " | " << std::setw(e.got.column + 1) << "";
|
std::cout << " " << std::setw(lineNumberWidthInConsole) << "" << " | " << std::setw(e.got.column) << "";
|
||||||
LX::PrintStringAsColor(errorSquiggle, LX::Color::LIGHT_RED);
|
LX::PrintStringAsColor(errorSquiggle, LX::Color::LIGHT_RED);
|
||||||
std::cout << "\n";
|
std::cout << "\n";
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ namespace LX
|
|||||||
TOKEN_CASE(Token::CLOSE_BRACKET);
|
TOKEN_CASE(Token::CLOSE_BRACKET);
|
||||||
TOKEN_CASE(Token::OPEN_PAREN);
|
TOKEN_CASE(Token::OPEN_PAREN);
|
||||||
TOKEN_CASE(Token::CLOSE_PAREN);
|
TOKEN_CASE(Token::CLOSE_PAREN);
|
||||||
|
TOKEN_CASE(Token::ASSIGN);
|
||||||
|
TOKEN_CASE(Token::INT_DEC);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return "Unknown: " + std::to_string(type);
|
return "Unknown: " + std::to_string(type);
|
||||||
@@ -102,7 +104,8 @@ namespace LX
|
|||||||
{ "else" , Token::ELSE },
|
{ "else" , Token::ELSE },
|
||||||
{ "elif" , Token::ELIF },
|
{ "elif" , Token::ELIF },
|
||||||
{ "func" , Token::FUNCTION },
|
{ "func" , Token::FUNCTION },
|
||||||
{ "return" , Token::RETURN }
|
{ "return" , Token::RETURN },
|
||||||
|
{ "int" , Token::INT_DEC }
|
||||||
};
|
};
|
||||||
|
|
||||||
// All the symbols supported by the lexer //
|
// All the symbols supported by the lexer //
|
||||||
@@ -114,7 +117,8 @@ namespace LX
|
|||||||
{ ']', Token::CLOSE_BRACE },
|
{ ']', Token::CLOSE_BRACE },
|
||||||
{ '(', Token::OPEN_PAREN },
|
{ '(', Token::OPEN_PAREN },
|
||||||
{ ')', Token::CLOSE_PAREN },
|
{ ')', Token::CLOSE_PAREN },
|
||||||
{ ',', Token::COMMA }
|
{ ',', Token::COMMA },
|
||||||
|
{ '=', Token::ASSIGN }
|
||||||
};
|
};
|
||||||
|
|
||||||
// All the single-char operators currently supported by the lexer with their token-enum equivalents //
|
// All the single-char operators currently supported by the lexer with their token-enum equivalents //
|
||||||
|
|||||||
@@ -144,6 +144,7 @@
|
|||||||
<ClCompile Include="src\AST-Loggers.cpp" />
|
<ClCompile Include="src\AST-Loggers.cpp" />
|
||||||
<ClCompile Include="src\GenIR.cpp" />
|
<ClCompile Include="src\GenIR.cpp" />
|
||||||
<ClCompile Include="src\Parser.cpp" />
|
<ClCompile Include="src\Parser.cpp" />
|
||||||
|
<ClCompile Include="src\Scope.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="inc\AST.h" />
|
<ClInclude Include="inc\AST.h" />
|
||||||
|
|||||||
@@ -26,6 +26,9 @@
|
|||||||
<ClCompile Include="src\AST-Loggers.cpp">
|
<ClCompile Include="src\AST-Loggers.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Scope.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="inc\AST.h">
|
<ClInclude Include="inc\AST.h">
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ namespace LX::AST
|
|||||||
class ReturnStatement : public Node
|
class ReturnStatement : public Node
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// Constructor to set values and automatically set type
|
// Constructor to set values and automatically set type //
|
||||||
ReturnStatement(std::unique_ptr<Node> val);
|
ReturnStatement(std::unique_ptr<Node> val);
|
||||||
|
|
||||||
// Function for generating LLVN IR (Intermediate representation) //
|
// Function for generating LLVN IR (Intermediate representation) //
|
||||||
@@ -78,4 +78,24 @@ namespace LX::AST
|
|||||||
// What it is returning (can be null) //
|
// What it is returning (can be null) //
|
||||||
std::unique_ptr<Node> m_Val;
|
std::unique_ptr<Node> m_Val;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Node to represent the declaration of a variable within the AST //
|
||||||
|
class VariableDeclaration : public Node
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Constructor to set values and automatically set type //
|
||||||
|
VariableDeclaration(const std::string& name);
|
||||||
|
|
||||||
|
// Function for generating LLVN IR (Intermediate representation) //
|
||||||
|
llvm::Value* GenIR(InfoLLVM& LLVM) override;
|
||||||
|
|
||||||
|
// Function to log the node to a file //
|
||||||
|
void Log(std::ofstream* log, unsigned depth) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Name of the variable //
|
||||||
|
std::string m_Name;
|
||||||
|
|
||||||
|
// Doesnt need to store type as everything is currently int //
|
||||||
|
};
|
||||||
}
|
}
|
||||||
@@ -66,4 +66,9 @@ namespace LX::AST
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Function for generating LLVN IR (Intermediate representation) //
|
||||||
|
llvm::Value* VariableDeclaration::GenIR(InfoLLVM& LLVM)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
67
Parser/src/Scope.cpp
Normal file
67
Parser/src/Scope.cpp
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
#include <Parser.h>
|
||||||
|
|
||||||
|
#include <Util.h>
|
||||||
|
|
||||||
|
namespace LX
|
||||||
|
{
|
||||||
|
// Util function for getting a pointer to an item from a map //
|
||||||
|
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 //
|
||||||
|
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;
|
||||||
|
|
||||||
|
// Loops over the scope and it's child to find the variable //
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// Gets the variable (if it exists) //
|
||||||
|
Variable* var = GetFromMap(name, current->m_LocalVariables);
|
||||||
|
|
||||||
|
// Returns the variable if it exists //
|
||||||
|
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();
|
||||||
|
|
||||||
|
} while (current != nullptr);
|
||||||
|
|
||||||
|
// Else returns a nullptr and lets the caller handle the error checking //
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets a variable from the scope by it's name //
|
||||||
|
Scope::Variable* Scope::GetVarOfName(const std::string& name)
|
||||||
|
{
|
||||||
|
// Gets the variable (if it exists) //
|
||||||
|
Variable* var = GetVarOfNameImpl(name);
|
||||||
|
|
||||||
|
// Throws an error if the variable doesn't exist //
|
||||||
|
ThrowIf<VariableDoesntExist>(var == nullptr);
|
||||||
|
|
||||||
|
// 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()
|
||||||
{
|
{
|
||||||
return 1 + 2
|
int a = 5
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user