diff --git a/IR-Generator/inc/Parser.h b/IR-Generator/inc/Parser.h index 9c9a361..ac5fdb0 100644 --- a/IR-Generator/inc/Parser.h +++ b/IR-Generator/inc/Parser.h @@ -30,6 +30,7 @@ namespace LX::AST NUMBER_LITERAL, OPERATION, + FUNCTION_CALL, // Variable manipulation // @@ -57,6 +58,9 @@ namespace LX::AST // Function to log the node to a file // virtual void Log(unsigned depth) = 0; + // Function to get the node's type name // + virtual const char* TypeName() = 0; + // Function for generating C/C++ code (Currently not implemented) // //virtual void GenC() = 0; diff --git a/LX-Build/Main.cs b/LX-Build/Main.cs index 78c2d36..3c2b401 100644 --- a/LX-Build/Main.cs +++ b/LX-Build/Main.cs @@ -49,6 +49,7 @@ namespace LX_Build { // Quits if the IR Generation fails // // The C++ script handles all of the error message outputting // + Console.WriteLine("LX_API.GenIR threw an error"); return; } diff --git a/Parser/inc/AST.h b/Parser/inc/AST.h index b919755..4a1fe04 100644 --- a/Parser/inc/AST.h +++ b/Parser/inc/AST.h @@ -15,6 +15,9 @@ namespace LX llvm::LLVMContext context; llvm::Module module; llvm::IRBuilder<> builder; + + // All IR functions that have been generated // + std::unordered_map functions; }; } @@ -32,6 +35,9 @@ namespace LX::AST // Function to log the node to a file, will throw an error if called on this class // void Log(unsigned depth) override; + // Function to get the node's type name, will throw an error if called on this class // + virtual const char* TypeName() override; + // The nodes that are contained within this node // std::vector> nodes; }; @@ -49,6 +55,9 @@ namespace LX::AST // Function to log the node to a file // void Log(unsigned depth) override; + // Function to get the node's type name // + const char* TypeName() override; + private: // The number it stores // // Yes the number is stored as a string, It's horrible I know // @@ -68,6 +77,9 @@ namespace LX::AST // Function to log the node to a file // void Log(unsigned depth) override; + // Function to get the node's type name // + const char* TypeName() override; + private: // The sides of the operation // // Unary operations are handled by a different class // @@ -90,6 +102,9 @@ namespace LX::AST // Function to log the node to a file // void Log(unsigned depth) override; + // Function to get the node's type name // + const char* TypeName() override; + private: // What it is returning (can be null) // std::unique_ptr m_Val; @@ -108,6 +123,9 @@ namespace LX::AST // Function to log the node to a file // void Log(unsigned depth) override; + // Function to get the node's type name // + const char* TypeName() override; + private: // Name of the variable // std::string m_Name; @@ -128,6 +146,9 @@ namespace LX::AST // Function to log the node to a file // void Log(unsigned depth) override; + // Function to get the node's type name // + const char* TypeName() override; + private: // Name of the variable // std::string m_Name; @@ -149,8 +170,35 @@ namespace LX::AST // Function to log the node to a file // void Log(unsigned depth) override; + // Function to get the node's type name // + const char* TypeName() override; + private: // The name of the variable // std::string m_Name; }; + + // Node to represent calling a function within the AST // + class FunctionCall : public Node + { + public: + // Constructor to set the name of the function and any args it may have // + FunctionCall(const std::string& funcName, std::vector>& args); + + // Function for generating LLVM IR (Intermediate representation) // + llvm::Value* GenIR(InfoLLVM& LLVM, FunctionScope& func) override; + + // Function to log the niode to a file // + void Log(unsigned depth) override; + + // Function to get the node's type name // + const char* TypeName() override; + + private: + // The name of the function // + std::string m_Name; + + // Any arguments to pass into the function // + std::vector> m_Args; + }; } \ No newline at end of file diff --git a/Parser/src/AST/AST-Constructors.cpp b/Parser/src/AST/AST-Constructors.cpp index e01f6db..6830189 100644 --- a/Parser/src/AST/AST-Constructors.cpp +++ b/Parser/src/AST/AST-Constructors.cpp @@ -63,4 +63,9 @@ namespace LX::AST VariableAccess::VariableAccess(const std::string& name) : Node(Node::VARIABLE_ACCESS), m_Name(name) {} + + // Passes constructor args to values and sets type // + FunctionCall::FunctionCall(const std::string& name, std::vector>& args) + : Node(Node::FUNCTION_CALL), m_Name(name), m_Args(std::move(args)) + {} } diff --git a/Parser/src/AST/AST-LLVM.cpp b/Parser/src/AST/AST-LLVM.cpp index c8bfc25..1334ef3 100644 --- a/Parser/src/AST/AST-LLVM.cpp +++ b/Parser/src/AST/AST-LLVM.cpp @@ -113,4 +113,16 @@ namespace LX::AST { return func.AccessVar(m_Name, LLVM); } + + llvm::Value* FunctionCall::GenIR(InfoLLVM& LLVM, FunctionScope& func) + { + std::vector evaluatedArgs; + + for (std::unique_ptr& node : m_Args) + { + evaluatedArgs.push_back(node->GenIR(LLVM, func)); + } + + return LLVM.builder.CreateCall(LLVM.functions[m_Name], evaluatedArgs, "call_tmp"); + } } diff --git a/Parser/src/AST/AST-Loggers.cpp b/Parser/src/AST/AST-Loggers.cpp index f4a2222..b68ea72 100644 --- a/Parser/src/AST/AST-Loggers.cpp +++ b/Parser/src/AST/AST-Loggers.cpp @@ -9,11 +9,21 @@ namespace LX::AST throw int(); // <- TODO: Make an error for this } + const char* MultiNode::TypeName() + { + throw int(); // <- TODO: Make an error for this + } + void NumberLiteral::Log(unsigned depth) { Log::out(std::string(depth, '\t'), "Number: ", m_Number); } + const char* NumberLiteral::TypeName() + { + return "Number Literal"; + } + void Operation::Log(unsigned depth) { Log::out(std::string(depth, '\t'), "Operation {", ToString(m_Operand), "}:"); @@ -25,6 +35,11 @@ namespace LX::AST m_Rhs->Log(depth + 2); } + const char* Operation::TypeName() + { + return "Operation"; + } + void ReturnStatement::Log(unsigned depth) { Log::out(std::string(depth, '\t'), "Return"); @@ -41,11 +56,21 @@ namespace LX::AST } } + const char* ReturnStatement::TypeName() + { + return "Return"; + } + void VariableDeclaration::Log(unsigned depth) { Log::out(std::string(depth, '\t'), "Variable declaration: ", m_Name); } + const char* VariableDeclaration::TypeName() + { + return "Variable declaration"; + } + void VariableAssignment::Log(unsigned depth) { Log::out(std::string(depth, '\t'), "Variable assignment:"); @@ -55,8 +80,35 @@ namespace LX::AST m_Value->Log(depth + 2); } + const char* VariableAssignment::TypeName() + { + return "Variable assignment"; + } + void VariableAccess::Log(unsigned depth) { Log::out(std::string(depth, '\t'), "Variable: ", m_Name); } + + const char* VariableAccess::TypeName() + { + return "Variable access"; + } + + void FunctionCall::Log(unsigned depth) + { + Log::out(std::string(depth, '\t'), "Function call{", m_Name, "}:"); + + if (m_Args.size() != 0) + { + Log::out(std::string(depth + 1, '\t'), "Args:"); + + for (auto& arg : m_Args) { arg->Log(depth + 2); } + } + } + + const char* FunctionCall::TypeName() + { + return "Function call"; + } } diff --git a/Parser/src/GenIR.cpp b/Parser/src/GenIR.cpp index 0ee3188..007cc70 100644 --- a/Parser/src/GenIR.cpp +++ b/Parser/src/GenIR.cpp @@ -30,36 +30,52 @@ namespace LX // Generates the LLVM IR for the given function // static void GenerateFunctionIR(FunctionDefinition& funcAST, InfoLLVM& LLVM) { - // Creates the functions signature and return type // - - std::cout << funcAST.params.size() << std::endl; - - std::vector funcParams(funcAST.params.size(), LLVM.builder.getInt32Ty()); - - llvm::FunctionType* retType = llvm::FunctionType::get(llvm::Type::getInt32Ty(LLVM.context), funcParams, false); // <- Defaults to int currently - llvm::Function* func = llvm::Function::Create(retType, GetLinkageType(funcAST.name), funcAST.name, LLVM.module); - llvm::BasicBlock* entry = llvm::BasicBlock::Create(LLVM.context, funcAST.name + "-entry", func); - LLVM.builder.SetInsertPoint(entry); - - // Creates the storer of the variables/parameters // - - FunctionScope funcScope(funcAST.params, func); - - // Generates the IR within the function by looping over the nodes // - for (auto& node : funcAST.body) + try { - ThrowIf(IsValidTopLevelNode(node->m_Type) == false); // <- TODO: replace with actual error type - node->GenIR(LLVM, funcScope); + Log::LogNewSection("Generating ", funcAST.name, " LLVM IR"); + + // Creates the functions signature and return type // + + std::vector funcParams(funcAST.params.size(), LLVM.builder.getInt32Ty()); + + llvm::FunctionType* retType = llvm::FunctionType::get(llvm::Type::getInt32Ty(LLVM.context), funcParams, false); // <- Defaults to int currently + llvm::Function* func = llvm::Function::Create(retType, GetLinkageType(funcAST.name), funcAST.name, LLVM.module); + llvm::BasicBlock* entry = llvm::BasicBlock::Create(LLVM.context, funcAST.name + "-entry", func); + LLVM.builder.SetInsertPoint(entry); + + // Stores the function for other functions to call it // + + LLVM.functions[funcAST.name] = func; + + // Creates the storer of the variables/parameters // + + FunctionScope funcScope(funcAST.params, func); + + // Generates the IR within the function by looping over the nodes // + for (auto& node : funcAST.body) + { + ThrowIf(IsValidTopLevelNode(node->m_Type) == false); // <- TODO: replace with actual error type + + Log::out("Generating: ", node->TypeName()); + + node->GenIR(LLVM, funcScope); + } + + // Adds a terminator if there is none // + if (entry->getTerminator() == nullptr) + { + LLVM.builder.CreateRet(llvm::ConstantInt::get(llvm::Type::getInt32Ty(LLVM.context), 0, true)); + } + + // Verifies the function works // + ThrowIf(llvm::verifyFunction(*func, &llvm::errs())); // <- TODO: Make error type } - // Adds a terminator if there is none // - if (entry->getTerminator() == nullptr) + catch (...) { - LLVM.builder.CreateRet(llvm::ConstantInt::get(llvm::Type::getInt32Ty(LLVM.context), 0, true)); + __debugbreak(); + throw; } - - // Verifies the function works // - ThrowIf(llvm::verifyFunction(*func)); // <- TODO: Make error type } // Turns an abstract binary tree into LLVM intermediate representation // diff --git a/Parser/src/Parser.cpp b/Parser/src/Parser.cpp index 3c86f33..7b25161 100644 --- a/Parser/src/Parser.cpp +++ b/Parser/src/Parser.cpp @@ -24,6 +24,36 @@ namespace LX } } + std::unique_ptr ParseOperation(ParserInfo& p); + + // Part of ParsePrimary // + static std::unique_ptr ParseIdentifier(ParserInfo& p) + { + if (p.tokens[p.index + 1].type == Token::OPEN_PAREN) + { + std::string funcName = p.tokens[p.index].GetContents(); + p.index = p.index + 2; // Skips over open paren and func name + + std::vector> args; + + while (true) + { + args.push_back(ParseOperation(p)); + + if (p.tokens[p.index].type == Token::CLOSE_PAREN) + { + p.index++; + return std::make_unique(funcName, args); + } + + ThrowIf(p.tokens[p.index].type != Token::COMMA, Token::COMMA, p); + p.index++; + } + } + + return std::make_unique(p.tokens[p.index++].GetContents()); + } + // Base of the call stack to handle the simplest of tokens // static std::unique_ptr ParsePrimary(ParserInfo& p) { @@ -37,20 +67,7 @@ namespace LX // If an Identifier has got here it means a variable is being accessed // case Token::IDENTIFIER: - return std::make_unique(p.tokens[p.index++].GetContents()); - - // TODO: Fix this // - case Token::OPEN_BRACKET: - p.scopeDepth++; - p.index++; - return nullptr; - - // TODO: Fix this // - case Token::CLOSE_BRACE: - ThrowIf(p.scopeDepth == 0, Token::UNDEFINED, p.tokens[p.index], "need a different error", p); - p.scopeDepth--; - p.index++; - return nullptr; + return ParseIdentifier(p); // Returns nullptr, the parsing function that recives that value will decide if that is valid // default: diff --git a/example/main.lx b/example/main.lx index c0cd289..435e457 100644 --- a/example/main.lx +++ b/example/main.lx @@ -3,12 +3,19 @@ func add(int a, int b) return a + b } +func sub(int c, int d) +{ + return add(c, 0 - d) +} + +func mul(int e, int f) +{ + return e * f +} + func main() { - int a - a = 5 + 2 + int g = mul(add(7, 5), sub(5, 3)) - int b = 6 + 1 - - return a + b + return g }