mirror of
https://github.com/PashaBibko/LX.git
synced 2026-04-03 17:39:02 +00:00
Added VarAssign, VarAccess and MultiNode
This commit is contained in:
@@ -26,11 +26,20 @@ namespace LX::AST
|
||||
// Used so a pointer to Node can be used and then turned into it's true type //
|
||||
enum NodeType
|
||||
{
|
||||
// "Nodes" //
|
||||
|
||||
MULTI_NODE,
|
||||
|
||||
// General Nodes //
|
||||
|
||||
NUMBER_LITERAL,
|
||||
OPERATION,
|
||||
|
||||
// Variable manipulation //
|
||||
|
||||
VARIABLE_DECLARATION,
|
||||
VARIABLE_ASSIGNMENT,
|
||||
VARIABLE_ACCESS,
|
||||
|
||||
// Control flow Nodes //
|
||||
|
||||
|
||||
@@ -23,6 +23,22 @@ namespace LX
|
||||
|
||||
namespace LX::AST
|
||||
{
|
||||
class MultiNode : public Node
|
||||
{
|
||||
public:
|
||||
// Constructor to auto set type //
|
||||
MultiNode();
|
||||
|
||||
// Function for generating LLVM IR (Intermediate representation), will throw error if called on this class //
|
||||
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;
|
||||
|
||||
// The nodes that are contained within this node //
|
||||
std::vector<std::unique_ptr<Node>> nodes;
|
||||
};
|
||||
|
||||
// Node to represent any number within the AST //
|
||||
class NumberLiteral : public Node
|
||||
{
|
||||
@@ -30,7 +46,7 @@ namespace LX::AST
|
||||
// Constructor to set values and automatically set type //
|
||||
NumberLiteral(std::string num);
|
||||
|
||||
// Function for generating LLVN IR (Intermediate representation) //
|
||||
// Function for generating LLVM IR (Intermediate representation) //
|
||||
llvm::Value* GenIR(InfoLLVM& LLVM) override;
|
||||
|
||||
// Function to log the node to a file //
|
||||
@@ -49,7 +65,7 @@ namespace LX::AST
|
||||
// Constructor to set values and automatically set type //
|
||||
Operation(std::unique_ptr<Node> lhs, Token::TokenType op, std::unique_ptr<Node> rhs);
|
||||
|
||||
// Function for generating LLVN IR (Intermediate representation) //
|
||||
// Function for generating LLVM IR (Intermediate representation) //
|
||||
llvm::Value* GenIR(InfoLLVM& LLVM) override;
|
||||
|
||||
// Function to log the node to a file //
|
||||
@@ -71,7 +87,7 @@ namespace LX::AST
|
||||
// Constructor to set values and automatically set type //
|
||||
ReturnStatement(std::unique_ptr<Node> val);
|
||||
|
||||
// Function for generating LLVN IR (Intermediate representation) //
|
||||
// Function for generating LLVM IR (Intermediate representation) //
|
||||
llvm::Value* GenIR(InfoLLVM& LLVM) override;
|
||||
|
||||
// Function to log the node to a file //
|
||||
@@ -89,7 +105,7 @@ namespace LX::AST
|
||||
// Constructor to set values and automatically set type //
|
||||
VariableDeclaration(const std::string& name);
|
||||
|
||||
// Function for generating LLVN IR (Intermediate representation) //
|
||||
// Function for generating LLVM IR (Intermediate representation) //
|
||||
llvm::Value* GenIR(InfoLLVM& LLVM) override;
|
||||
|
||||
// Function to log the node to a file //
|
||||
@@ -101,4 +117,43 @@ namespace LX::AST
|
||||
|
||||
// Doesnt need to store type as everything is currently int //
|
||||
};
|
||||
|
||||
// Node to represent the assignment of a variable within the AST //
|
||||
class VariableAssignment : public Node
|
||||
{
|
||||
public:
|
||||
// Constructor to set values and automatically set type //
|
||||
VariableAssignment(const std::string& name, std::unique_ptr<AST::Node> val);
|
||||
|
||||
// Function for generating LLVM 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;
|
||||
|
||||
// The value that will be assigned to the value //
|
||||
std::unique_ptr<Node> m_Value;
|
||||
};
|
||||
|
||||
// Node to represent accessing a variable within the AST //
|
||||
class VariableAccess : public Node
|
||||
{
|
||||
public:
|
||||
// Constructor to set values and automatically set type //
|
||||
VariableAccess(const std::string& name);
|
||||
|
||||
// Function for generating LLVM 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:
|
||||
// The name of the variable //
|
||||
std::string m_Name;
|
||||
};
|
||||
}
|
||||
@@ -27,6 +27,11 @@ namespace LX::AST
|
||||
: m_Type(type)
|
||||
{}
|
||||
|
||||
// Automatically sets type //
|
||||
MultiNode::MultiNode()
|
||||
: Node(Node::MULTI_NODE), nodes{}
|
||||
{}
|
||||
|
||||
// Passes constructor args to values and sets type //
|
||||
NumberLiteral::NumberLiteral(std::string num)
|
||||
: Node(Node::NUMBER_LITERAL), m_Number(num)
|
||||
@@ -46,4 +51,14 @@ namespace LX::AST
|
||||
VariableDeclaration::VariableDeclaration(const std::string& name)
|
||||
: Node(Node::VARIABLE_DECLARATION), m_Name(name)
|
||||
{}
|
||||
|
||||
// Passes constructor args to values and sets type //
|
||||
VariableAssignment::VariableAssignment(const std::string& name, std::unique_ptr<AST::Node> val)
|
||||
: Node(Node::VARIABLE_ASSIGNMENT), m_Name(name), m_Value(std::move(val))
|
||||
{}
|
||||
|
||||
// Passes constructor args to values and sets type //
|
||||
VariableAccess::VariableAccess(const std::string& name)
|
||||
: Node(Node::VARIABLE_ACCESS), m_Name(name)
|
||||
{}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,13 @@
|
||||
|
||||
namespace LX::AST
|
||||
{
|
||||
// Function for generating LLVN IR (Intermediate representation) //
|
||||
// Function for genrating LLVM IR (Intermediate representation), will throw an error if called on this class //
|
||||
llvm::Value* MultiNode::GenIR(InfoLLVM & LLVM)
|
||||
{
|
||||
throw int(); // <- TODO: Make an error type
|
||||
}
|
||||
|
||||
// Function for generating LLVM IR (Intermediate representation) //
|
||||
llvm::Value* NumberLiteral::GenIR(InfoLLVM& LLVM)
|
||||
{
|
||||
// Converts the string to it's int equivalent //
|
||||
@@ -21,7 +27,7 @@ namespace LX::AST
|
||||
return out;
|
||||
}
|
||||
|
||||
// Function for generating LLVN IR (Intermediate representation) //
|
||||
// Function for generating LLVM IR (Intermediate representation) //
|
||||
llvm::Value* Operation::GenIR(InfoLLVM& LLVM)
|
||||
{
|
||||
// Generates the IR for both sides of the operation //
|
||||
@@ -44,7 +50,7 @@ namespace LX::AST
|
||||
return out;
|
||||
}
|
||||
|
||||
// Function for generating LLVN IR (Intermediate representation) //
|
||||
// Function for generating LLVM IR (Intermediate representation) //
|
||||
llvm::Value* ReturnStatement::GenIR(InfoLLVM& LLVM)
|
||||
{
|
||||
// Checks if it is a void return //
|
||||
@@ -67,7 +73,7 @@ namespace LX::AST
|
||||
}
|
||||
}
|
||||
|
||||
// Function for generating LLVN IR (Intermediate representation) //
|
||||
// Function for generating LLVM IR (Intermediate representation) //
|
||||
llvm::Value* VariableDeclaration::GenIR(InfoLLVM& LLVM)
|
||||
{
|
||||
// Creates the variable within the scope //
|
||||
@@ -76,4 +82,14 @@ namespace LX::AST
|
||||
// Creates the declaration within the IR //
|
||||
return LLVM.builder.CreateAlloca(LLVM.builder.getInt32Ty(), nullptr, m_Name);
|
||||
}
|
||||
|
||||
llvm::Value* VariableAssignment::GenIR(InfoLLVM& LLVM)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
llvm::Value* VariableAccess::GenIR(InfoLLVM& LLVM)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
|
||||
namespace LX::AST
|
||||
{
|
||||
void Node::Log(std::ofstream* log, unsigned depth)
|
||||
void MultiNode::Log(std::ofstream* log, unsigned depth)
|
||||
{
|
||||
(*log) << std::string(depth, '\t') << "NULL node";
|
||||
throw int(); // <- TODO: Make an error for this
|
||||
}
|
||||
|
||||
void NumberLiteral::Log(std::ofstream* log, unsigned depth)
|
||||
@@ -46,4 +46,19 @@ namespace LX::AST
|
||||
(*log) << std::string(depth, '\t');
|
||||
(*log) << "Variable declaration: " << m_Name << "\n";
|
||||
}
|
||||
|
||||
void VariableAssignment::Log(std::ofstream* 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);
|
||||
}
|
||||
|
||||
void VariableAccess::Log(std::ofstream* log, unsigned depth)
|
||||
{
|
||||
(*log) << std::string(depth, '\t');
|
||||
(*log) << "Variable: " << m_Name << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,6 @@ namespace LX
|
||||
{
|
||||
// Checks if the next token is an operator //
|
||||
// TODO: Add more than just add //
|
||||
// TODO: Make this not crash when at the end //
|
||||
if (p.index + 1 < p.len) [[likely]]
|
||||
{
|
||||
if (p.tokens[p.index + 1].type == Token::ADD)
|
||||
@@ -120,21 +119,61 @@ namespace LX
|
||||
|
||||
// Checks for the variable name //
|
||||
ThrowIf<UnexpectedToken>(p.tokens[p.index].type != Token::IDENTIFIER, Token::IDENTIFIER, "", p.tokens[p.index]);
|
||||
std::string name = p.tokens[p.index].GetContents();
|
||||
p.index++; // <- Goes over the identifier token
|
||||
|
||||
// Returns the variable declaration as an AST node by creating it with it's name //
|
||||
return std::make_unique<AST::VariableDeclaration>(p.tokens[p.index - 1].GetContents());
|
||||
// Returns the declaration if there is no default assignment to the variable //
|
||||
if (p.tokens[p.index].type != Token::ASSIGN)
|
||||
{
|
||||
// Creates the variable name from the contents of the token and returns it //
|
||||
return std::make_unique<AST::VariableDeclaration>(name);
|
||||
}
|
||||
|
||||
p.index++; // Skips over Token::ASSIGN
|
||||
|
||||
// Gets the value to be assigned to the variable //
|
||||
std::unique_ptr<AST::Node> defaultVal = ParsePrimary(p);
|
||||
ThrowIf<UnexpectedToken>(defaultVal.get() == nullptr, Token::UNDEFINED, "value", p.tokens[p.index - 1]);
|
||||
|
||||
return std::make_unique<AST::VariableDeclaration>(name);
|
||||
}
|
||||
|
||||
// Else goes down the call stack //
|
||||
return ParseReturn(p);
|
||||
}
|
||||
|
||||
// Handles variable assignments, if not calls ParseVarDeclaration //
|
||||
static std::unique_ptr<AST::Node> ParseVarAssignment(Parser& p)
|
||||
{
|
||||
// Checks if the next token is an equals //
|
||||
if (p.index + 1 < p.len) [[likely]]
|
||||
{
|
||||
if (p.tokens[p.index + 1].type == Token::ASSIGN)
|
||||
{
|
||||
// Gets the variable that is being assigned too //
|
||||
ThrowIf<UnexpectedToken>(p.tokens[p.index].type != Token::IDENTIFIER, Token::IDENTIFIER, "", p.tokens[p.index]);
|
||||
std::string name = p.tokens[p.index].GetContents();
|
||||
|
||||
// Skips over the assign token and name of the variable //
|
||||
p.index = p.index + 2;
|
||||
|
||||
// Gets the value that is being assigned //
|
||||
std::unique_ptr<AST::Node> value = ParseOperation(p);
|
||||
|
||||
// Returns an AST node of the variable assignment with it's name and value //
|
||||
return std::make_unique<AST::VariableAssignment>(name, std::move(value));
|
||||
}
|
||||
}
|
||||
|
||||
// Else goes down the call stack //
|
||||
return ParseVarDeclaration(p);
|
||||
}
|
||||
|
||||
// Helper function to call the top of the Parse-Call-Stack //
|
||||
static inline std::unique_ptr<AST::Node> Parse(Parser& p)
|
||||
{
|
||||
// Parses the current token //
|
||||
std::unique_ptr<AST::Node> out = ParseVarDeclaration(p);
|
||||
std::unique_ptr<AST::Node> out = ParseVarAssignment(p);
|
||||
|
||||
// Checks it is valid before returning //
|
||||
ThrowIf<UnexpectedToken>(out == nullptr, Token::UNDEFINED, "top level statement", p.tokens[p.index - 1]);
|
||||
@@ -191,15 +230,32 @@ namespace LX
|
||||
// Loops over the body until it reaches the end //
|
||||
while (p.index < p.len && (p.tokens[p.index].type == Token::CLOSE_BRACKET && p.scopeDepth == 0) == false)
|
||||
{
|
||||
// Actually parses the function
|
||||
// Actually parses the function //
|
||||
std::unique_ptr<AST::Node> node = Parse(p);
|
||||
|
||||
// Expands the node if it contains multiple //
|
||||
if (node->m_Type == AST::Node::MULTI_NODE)
|
||||
{
|
||||
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); }
|
||||
|
||||
// Adds it to the vector
|
||||
// Adds it to the vector //
|
||||
func.body.push_back(std::move(containedNode));
|
||||
}
|
||||
}
|
||||
|
||||
// Else adds the singular node to the vector //
|
||||
else
|
||||
{
|
||||
// Logs the node to the log //
|
||||
if (log != nullptr) { node->Log(log, 0); }
|
||||
|
||||
// Adds it to the vector //
|
||||
func.body.push_back(std::move(node));
|
||||
}
|
||||
}
|
||||
|
||||
// Skips over closing bracket //
|
||||
p.index++;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
func main()
|
||||
{
|
||||
int result
|
||||
result = 3
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user