Added VarAssign, VarAccess and MultiNode

This commit is contained in:
Pasha Bibko
2025-04-28 19:59:45 +01:00
parent d8773d4020
commit 3ec6cc0c6e
7 changed files with 186 additions and 20 deletions

View File

@@ -26,11 +26,20 @@ namespace LX::AST
// Used so a pointer to Node can be used and then turned into it's true type // // Used so a pointer to Node can be used and then turned into it's true type //
enum NodeType enum NodeType
{ {
// "Nodes" //
MULTI_NODE,
// General Nodes // // General Nodes //
NUMBER_LITERAL, NUMBER_LITERAL,
OPERATION, OPERATION,
// Variable manipulation //
VARIABLE_DECLARATION, VARIABLE_DECLARATION,
VARIABLE_ASSIGNMENT,
VARIABLE_ACCESS,
// Control flow Nodes // // Control flow Nodes //

View File

@@ -23,6 +23,22 @@ namespace LX
namespace LX::AST 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 // // Node to represent any number within the AST //
class NumberLiteral : public Node class NumberLiteral : public Node
{ {
@@ -30,7 +46,7 @@ namespace LX::AST
// Constructor to set values and automatically set type // // Constructor to set values and automatically set type //
NumberLiteral(std::string num); NumberLiteral(std::string num);
// Function for generating LLVN IR (Intermediate representation) // // Function for generating LLVM IR (Intermediate representation) //
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 //
@@ -49,7 +65,7 @@ namespace LX::AST
// Constructor to set values and automatically set type // // Constructor to set values and automatically set type //
Operation(std::unique_ptr<Node> lhs, Token::TokenType op, std::unique_ptr<Node> rhs); 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; llvm::Value* GenIR(InfoLLVM& LLVM) override;
// Function to log the node to a file // // Function to log the node to a file //
@@ -71,7 +87,7 @@ namespace LX::AST
// 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 LLVM IR (Intermediate representation) //
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 //
@@ -89,7 +105,7 @@ namespace LX::AST
// Constructor to set values and automatically set type // // Constructor to set values and automatically set type //
VariableDeclaration(const std::string& name); 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; llvm::Value* GenIR(InfoLLVM& LLVM) override;
// Function to log the node to a file // // 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 // // 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;
};
} }

View File

@@ -27,6 +27,11 @@ namespace LX::AST
: m_Type(type) : m_Type(type)
{} {}
// Automatically sets type //
MultiNode::MultiNode()
: Node(Node::MULTI_NODE), nodes{}
{}
// Passes constructor args to values and sets type // // Passes constructor args to values and sets type //
NumberLiteral::NumberLiteral(std::string num) NumberLiteral::NumberLiteral(std::string num)
: Node(Node::NUMBER_LITERAL), m_Number(num) : Node(Node::NUMBER_LITERAL), m_Number(num)
@@ -46,4 +51,14 @@ namespace LX::AST
VariableDeclaration::VariableDeclaration(const std::string& name) VariableDeclaration::VariableDeclaration(const std::string& name)
: Node(Node::VARIABLE_DECLARATION), m_Name(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)
{}
} }

View File

@@ -6,7 +6,13 @@
namespace LX::AST 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) llvm::Value* NumberLiteral::GenIR(InfoLLVM& LLVM)
{ {
// Converts the string to it's int equivalent // // Converts the string to it's int equivalent //
@@ -21,7 +27,7 @@ namespace LX::AST
return out; return out;
} }
// Function for generating LLVN IR (Intermediate representation) // // Function for generating LLVM IR (Intermediate representation) //
llvm::Value* Operation::GenIR(InfoLLVM& LLVM) llvm::Value* Operation::GenIR(InfoLLVM& LLVM)
{ {
// Generates the IR for both sides of the operation // // Generates the IR for both sides of the operation //
@@ -44,7 +50,7 @@ namespace LX::AST
return out; return out;
} }
// Function for generating LLVN IR (Intermediate representation) // // Function for generating LLVM IR (Intermediate representation) //
llvm::Value* ReturnStatement::GenIR(InfoLLVM& LLVM) llvm::Value* ReturnStatement::GenIR(InfoLLVM& LLVM)
{ {
// Checks if it is a void return // // 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) llvm::Value* VariableDeclaration::GenIR(InfoLLVM& LLVM)
{ {
// Creates the variable within the scope // // Creates the variable within the scope //
@@ -76,4 +82,14 @@ namespace LX::AST
// Creates the declaration within the IR // // Creates the declaration within the IR //
return LLVM.builder.CreateAlloca(LLVM.builder.getInt32Ty(), nullptr, m_Name); 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;
}
} }

View File

@@ -4,9 +4,9 @@
namespace LX::AST 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) void NumberLiteral::Log(std::ofstream* log, unsigned depth)
@@ -46,4 +46,19 @@ namespace LX::AST
(*log) << std::string(depth, '\t'); (*log) << std::string(depth, '\t');
(*log) << "Variable declaration: " << m_Name << "\n"; (*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';
}
} }

View File

@@ -67,7 +67,6 @@ namespace LX
{ {
// Checks if the next token is an operator // // Checks if the next token is an operator //
// TODO: Add more than just add // // TODO: Add more than just add //
// TODO: Make this not crash when at the end //
if (p.index + 1 < p.len) [[likely]] if (p.index + 1 < p.len) [[likely]]
{ {
if (p.tokens[p.index + 1].type == Token::ADD) if (p.tokens[p.index + 1].type == Token::ADD)
@@ -120,21 +119,61 @@ namespace LX
// Checks for the variable name // // Checks for the variable name //
ThrowIf<UnexpectedToken>(p.tokens[p.index].type != Token::IDENTIFIER, Token::IDENTIFIER, "", p.tokens[p.index]); 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 p.index++; // <- Goes over the identifier token
// Returns the variable declaration as an AST node by creating it with it's name // // Returns the declaration if there is no default assignment to the variable //
return std::make_unique<AST::VariableDeclaration>(p.tokens[p.index - 1].GetContents()); 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 // // Else goes down the call stack //
return ParseReturn(p); 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 // // Helper function to call the top of the Parse-Call-Stack //
static inline std::unique_ptr<AST::Node> Parse(Parser& p) static inline std::unique_ptr<AST::Node> Parse(Parser& p)
{ {
// Parses the current token // // 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 // // Checks it is valid before returning //
ThrowIf<UnexpectedToken>(out == nullptr, Token::UNDEFINED, "top level statement", p.tokens[p.index - 1]); ThrowIf<UnexpectedToken>(out == nullptr, Token::UNDEFINED, "top level statement", p.tokens[p.index - 1]);
@@ -191,14 +230,31 @@ namespace LX
// Loops over the body until it reaches the end // // 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) 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); std::unique_ptr<AST::Node> node = Parse(p);
// Logs the node to the log // // Expands the node if it contains multiple //
if (log != nullptr) { node->Log(log, 0); } 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(node)); 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 // // Skips over closing bracket //

View File

@@ -1,4 +1,4 @@
func main() func main()
{ {
int result result = 3
} }