Improved syntax for functions

Added logging system for AST nodes as well.
This commit is contained in:
Pasha Bibko
2025-04-24 21:34:30 +01:00
parent 099e543e95
commit 321a7fea18
8 changed files with 74 additions and 27 deletions

View File

@@ -81,6 +81,8 @@ namespace LX
OPEN_BRACE, CLOSE_BRACE, OPEN_BRACE, CLOSE_BRACE,
OPEN_PAREN, CLOSE_PAREN, OPEN_PAREN, CLOSE_PAREN,
COMMA,
// Operators // // Operators //
ADD, SUB, MUL, DIV, ADD, SUB, MUL, DIV,

View File

@@ -27,7 +27,6 @@ namespace LX::AST
{ {
// General Nodes // // General Nodes //
IDENTIFIER,
NUMBER_LITERAL, NUMBER_LITERAL,
OPERATION, OPERATION,
@@ -48,6 +47,9 @@ namespace LX::AST
// Function for generating LLVN IR (Intermediate representation) // // Function for generating LLVN IR (Intermediate representation) //
virtual llvm::Value* GenIR(InfoLLVM& LLVM) = 0; virtual llvm::Value* GenIR(InfoLLVM& LLVM) = 0;
// Function to log the node to a file //
virtual void Log(std::ofstream* log, unsigned depth) = 0;
// Function for generating C/C++ code (Currently not implemented) // // Function for generating C/C++ code (Currently not implemented) //
//virtual void GenC() = 0; //virtual void GenC() = 0;

View File

@@ -178,9 +178,11 @@ int main(int argc, char** argv)
LX::PrintStringAsColor("Error: ", LX::Color::LIGHT_RED); LX::PrintStringAsColor("Error: ", LX::Color::LIGHT_RED);
std::cout << "Invalid character found in "; std::cout << "Invalid character found in ";
LX::PrintStringAsColor(inpPath.filename().string(), LX::Color::WHITE); LX::PrintStringAsColor(inpPath.filename().string(), LX::Color::WHITE);
std::cout << ":\n"; std::cout << " {";
LX::PrintStringAsColor(std::string(1, e.invalid), LX::Color::LIGHT_RED);
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); 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";
@@ -215,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) << ""; std::cout << " " << std::setw(lineNumberWidthInConsole) << "" << " | " << std::setw(e.got.column + 1) << "";
LX::PrintStringAsColor(errorSquiggle, LX::Color::LIGHT_RED); LX::PrintStringAsColor(errorSquiggle, LX::Color::LIGHT_RED);
std::cout << "\n"; std::cout << "\n";

View File

@@ -113,7 +113,8 @@ namespace LX
{ '[', Token::OPEN_BRACE }, { '[', Token::OPEN_BRACE },
{ ']', Token::CLOSE_BRACE }, { ']', Token::CLOSE_BRACE },
{ '(', Token::OPEN_PAREN }, { '(', Token::OPEN_PAREN },
{ ')', Token::CLOSE_PAREN } { ')', Token::CLOSE_PAREN },
{ ',', Token::COMMA }
}; };
// 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 //

View File

@@ -16,9 +16,6 @@ namespace LX
llvm::Module module; llvm::Module module;
llvm::IRBuilder<> builder; llvm::IRBuilder<> builder;
}; };
// Function to turn a AST node into string //
std::string ToString(std::unique_ptr<AST::Node>& node);
} }
namespace LX::AST namespace LX::AST
@@ -33,6 +30,9 @@ namespace LX::AST
// Function for generating LLVN IR (Intermediate representation) // // Function for generating LLVN IR (Intermediate representation) //
llvm::Value* GenIR(InfoLLVM& LLVM) override; llvm::Value* GenIR(InfoLLVM& LLVM) override;
// Function to log the node to a file //
void Log(std::ofstream* log, unsigned depth) override;
private: private:
// The number it stores // // The number it stores //
// Yes the number is stored as a string, It's horrible I know // // Yes the number is stored as a string, It's horrible I know //
@@ -49,6 +49,9 @@ namespace LX::AST
// Function for generating LLVN IR (Intermediate representation) // // Function for generating LLVN IR (Intermediate representation) //
llvm::Value* GenIR(InfoLLVM& LLVM) override; llvm::Value* GenIR(InfoLLVM& LLVM) override;
// Function to log the node to a file //
void Log(std::ofstream* log, unsigned depth) override;
private: private:
// The sides of the operation // // The sides of the operation //
// Unary operations are handled by a different class // // Unary operations are handled by a different class //
@@ -68,6 +71,9 @@ namespace LX::AST
// Function for generating LLVN IR (Intermediate representation) // // Function for generating LLVN IR (Intermediate representation) //
llvm::Value* GenIR(InfoLLVM& LLVM) override; llvm::Value* GenIR(InfoLLVM& LLVM) override;
// Function to log the node to a file //
void Log(std::ofstream* log, unsigned depth) override;
private: private:
// 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;

View File

@@ -1,17 +1,43 @@
#include <AST.h> #include <AST.h>
namespace LX #include <fstream>
{
std::string ToString(std::unique_ptr<AST::Node>& node)
{
if (node == nullptr) { return "NULL Node"; }
switch (node->m_Type) namespace LX::AST
{
void Node::Log(std::ofstream* log, unsigned depth)
{
(*log) << std::string(depth, '\t') << "NULL node";
}
void NumberLiteral::Log(std::ofstream* log, unsigned depth)
{
(*log) << std::string(depth, '\t');
(*log) << "Number: " << m_Number << "\n";
}
void Operation::Log(std::ofstream* 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);
}
void ReturnStatement::Log(std::ofstream* log, unsigned depth)
{
(*log) << std::string(depth, '\t');
if (m_Val == nullptr)
{ {
case AST::Node::IDENTIFIER: return "IDENTIFIER"; (*log) << "Return\n";
case AST::Node::OPERATION: return "OPERATION"; }
case AST::Node::RETURN_STATEMENT: return "return";
case AST::Node::NUMBER_LITERAL: return "number"; else
{
(*log) << "Return:\n";
m_Val->Log(log, depth + 1);
} }
} }
} }

View File

@@ -42,12 +42,13 @@ namespace LX
case Token::NUMBER_LITERAL: case Token::NUMBER_LITERAL:
return std::make_unique<AST::NumberLiteral>(p.tokens[p.index++].GetContents()); return std::make_unique<AST::NumberLiteral>(p.tokens[p.index++].GetContents());
// // TODO: Fix this //
case Token::OPEN_BRACKET: case Token::OPEN_BRACKET:
p.scopeDepth++; p.scopeDepth++;
p.index++; p.index++;
return nullptr; return nullptr;
// TODO: Fix this //
case Token::CLOSE_BRACE: case Token::CLOSE_BRACE:
ThrowIf<UnexpectedToken>(p.scopeDepth == 0, Token::UNDEFINED, "need a different error", p.tokens[p.index]); ThrowIf<UnexpectedToken>(p.scopeDepth == 0, Token::UNDEFINED, "need a different error", p.tokens[p.index]);
p.scopeDepth--; p.scopeDepth--;
@@ -148,19 +149,31 @@ namespace LX
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]);
func.name = p.tokens[p.index++].GetContents(); func.name = p.tokens[p.index++].GetContents();
// Checks for opening paren '(' //
ThrowIf<UnexpectedToken>(p.tokens[p.index].type != Token::OPEN_PAREN, Token::OPEN_PAREN, "", p.tokens[p.index]);
p.index++;
// Loops over all the arguments of the function //
while (p.index < p.len && (p.tokens[p.index].type == Token::CLOSE_PAREN) == false)
{
p.index++;
}
// Skips over close bracket //
p.index++;
// Checks for opening bracket '{' // // Checks for opening bracket '{' //
ThrowIf<UnexpectedToken>(p.tokens[p.index].type != Token::OPEN_BRACKET, Token::OPEN_BRACKET, "", p.tokens[p.index]); ThrowIf<UnexpectedToken>(p.tokens[p.index].type != Token::OPEN_BRACKET, Token::OPEN_BRACKET, "", p.tokens[p.index]);
p.index++; p.index++;
// Loops over the body until it reaches the end // // Loops over the body until it reaches the end //
// TODO: Detect the end instead of looping over the entire token vector
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 // // Logs the node to the log //
SafeLog(log, ToString(node)); 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(node));

View File

@@ -1,9 +1,4 @@
func add func main()
{ {
return 1 + 2 return 1 + 2
} }
func main
{
return 375 + 32
}