diff --git a/.gitignore b/.gitignore index e4e44dc..53a8ff1 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ build/ CMakeCache.txt **/CMakeCache.txt Makefile +.antlr/ + diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..f33d6be --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "files.associations": { + "*.tcc": "cpp", + "istream": "cpp" + } +} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 267a39f..2e79759 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,6 +21,8 @@ ADD_CUSTOM_TARGET(HooBaseVisitor ALL DEPENDS ${ANTLR_GENERATED_DIR}/HooBaseVisit INCLUDE_DIRECTORIES(${ANTLR_GENERATED_DIR} ${ANTLR_INCLUDE_DIR}) +ADD_LIBRARY(hoocore STATIC HooCore.cpp HooCore.hpp Node.hpp) + ADD_EXECUTABLE(hoo Hoo.cpp Visitor.cpp ${ANTLR_GENERATED_DIR}/HooBaseVisitor.cpp diff --git a/Dockerfile b/Dockerfile index fefb54d..460f565 100644 --- a/Dockerfile +++ b/Dockerfile @@ -35,6 +35,7 @@ RUN apt-get install -y cmake clang-19 RUN apt-get install -y openjdk-21-jdk-headless maven RUN apt-get install -y llvm llvm-dev RUN apt-get install -y libedit-dev libzstd-dev libcurlpp-dev +RUN apt-get install -y libgtest-dev COPY --from=build /custom/antlr4-cpp-runtime/usr/ /usr/ COPY --from=build /custom/antlr4/antlr4-4.13.2-complete.jar /usr/local/lib/antlr4-4.13.2-complete.jar ENV CXX=/usr/bin/clang++-19 diff --git a/Hoo.g4 b/Hoo.g4 index 735311e..3f16832 100644 --- a/Hoo.g4 +++ b/Hoo.g4 @@ -2,12 +2,16 @@ grammar Hoo; import hoolexer; -literal: - DECIMAL_LITERAL | - FLOAT_LITERAL | - BOOL_LITERAL | - CHAR_LITERAL | - STRING_LITERAL | - TEXT_BLOCK; +statement: literalStatement; -unit: literal; \ No newline at end of file +literalStatement: literal ';'; + +literal: + DECIMAL_LITERAL + | FLOAT_LITERAL + | BOOL_LITERAL + | CHAR_LITERAL + | STRING_LITERAL + | TEXT_BLOCK; + +unit: statement; \ No newline at end of file diff --git a/HooCore.cpp b/HooCore.cpp new file mode 100644 index 0000000..af66f07 --- /dev/null +++ b/HooCore.cpp @@ -0,0 +1,52 @@ +#include "HooCore.hpp" +#include "HooLexer.h" +#include "HooParser.h" +#include "Visitor.hpp" + +std::any HooCore::compile(std::string &input, std::string &moduleName) +{ + try + { + antlr4::tree::ParseTree *tree = parse(input); + if (tree == nullptr) + { + std::cout << "Parse failed" << std::endl; + } + Visitor *visitor = new Visitor(moduleName); + auto result = visitor->visit(tree); + return result; + } + catch (const std::exception &e) + { + std::cerr << "Compilation Error: " << e.what() << std::endl; + return nullptr; + } + catch (...) + { + std::cerr << "Compilation Error: Unknown exception" << std::endl; + return nullptr; + } +} + +antlr4::tree::ParseTree *HooCore::parse(std::string &input) +{ + try + { + antlr4::ANTLRInputStream input_stream(input); + HooLexer lexer(&input_stream); + antlr4::CommonTokenStream tokens(&lexer); + HooParser parser(&tokens); + antlr4::tree::ParseTree *tree = parser.unit(); + return tree; + } + catch (const std::exception &e) + { + std::cerr << "Parse Error: " << e.what() << std::endl; + return nullptr; + } + catch (...) + { + std::cerr << "Parse Error: Unknown exception" << std::endl; + return nullptr; + } +} diff --git a/HooCore.hpp b/HooCore.hpp new file mode 100644 index 0000000..7e9b682 --- /dev/null +++ b/HooCore.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include "antlr4-runtime.h" + +#include + +class HooCore +{ +public: + HooCore() {} + ~HooCore() {} + +public: + static std::any compile(std::string &input, std::string &moduleName); + static antlr4::tree::ParseTree *parse(std::string &input); +}; diff --git a/Node.hpp b/Node.hpp new file mode 100644 index 0000000..89eb492 --- /dev/null +++ b/Node.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include + +enum NodeType +{ + NODE_IGNORE, + NODE_LITERAL +}; + +enum DataType +{ + DATATYPE_VOID, + DATATYPE_INTEGER, + DATATYPE_FLOAT, + DATATYPE_BOOL, + DATATYPE_CHAR, + DATATYPE_STRING +}; + +class Node +{ +private: + NodeType _nodeType; + DataType _dataType; + llvm::Value *_value; + +public: + Node(NodeType nodeType, DataType dataType, llvm::Value *value) : _nodeType(nodeType), _dataType(dataType), _value(value) {} + Node(const Node &other) : _nodeType(other._nodeType), _dataType(other._dataType), _value(other._value) {} + + NodeType getNodeType() const { return _nodeType; } + DataType getDataType() const { return _dataType; } + llvm::Value *getValue() const { return _value; } + +public: + virtual ~Node() = default; +}; \ No newline at end of file diff --git a/Visitor.cpp b/Visitor.cpp index 961f47e..3799c91 100644 --- a/Visitor.cpp +++ b/Visitor.cpp @@ -1,4 +1,5 @@ #include "Visitor.hpp" +#include "Node.hpp" #include #include @@ -13,24 +14,58 @@ Visitor::Visitor(std::string &moduleName) : _moduleName(moduleName), std::any Visitor::visitLiteral(HooParser::LiteralContext *ctx) { - // Implement your custom logic for visiting a LiteralContext here - // Example: if it's a decimal literal, return its value as a string - if (ctx->DECIMAL_LITERAL()) + auto value = ctx->DECIMAL_LITERAL(); + if (value) { - return ctx->DECIMAL_LITERAL()->getText(); + auto decimalText = value->getText(); + double decimalValue = std::stoll(decimalText); + llvm::Type *decimalType = llvm::Type::getInt64Ty(*_context); + llvm::Constant *decimalConstant = llvm::ConstantInt::get(decimalType, decimalValue, true); + return std::any{Node(NODE_LITERAL, DATATYPE_INTEGER, decimalConstant)}; } - // Add handling for other literal types as needed - return visitChildren(ctx); + + value = ctx->FLOAT_LITERAL(); + if (value) + { + auto floatText = value->getText(); + float floatValue = std::stof(floatText); + llvm::Type *floatType = llvm::Type::getFloatTy(*_context); + llvm::Constant *floatConstant = llvm::ConstantFP::get(floatType, floatValue); + return std::any{Node(NODE_LITERAL, DATATYPE_FLOAT, floatConstant)}; + } + + value = ctx->BOOL_LITERAL(); + if (value) + { + auto boolText = value->getText(); + auto boolValue = boolText == "true" ? 1 : 0; + llvm::Type *boolType = llvm::Type::getInt1Ty(*_context); + llvm::Constant *boolConstant = llvm::ConstantInt::get(boolType, boolValue, true); + return std::any{Node(NODE_LITERAL, DATATYPE_BOOL, boolConstant)}; + } + + value = ctx->CHAR_LITERAL(); + if (value) + { + auto charText = value->getText(); + char charValue = charText[1]; + llvm::Type *charType = llvm::Type::getInt8Ty(*_context); + llvm::Constant *charConstant = llvm::ConstantInt::get(charType, charValue, true); + return std::any{Node(NODE_LITERAL, DATATYPE_CHAR, charConstant)}; + } + + value = ctx->STRING_LITERAL(); + if (value) + { + auto stringText = value->getText(); + auto stringConstant = llvm::ConstantDataArray::getString(*_context, stringText); + return std::any{Node(NODE_LITERAL, DATATYPE_STRING, stringConstant)}; + } + + return std::any{Node(NODE_IGNORE, DATATYPE_VOID, nullptr)}; } std::any Visitor::visitUnit(HooParser::UnitContext *ctx) { - // Implement your custom logic for visiting a UnitContext here - // Example: if it's a literal, return its value as a string - if (ctx->literal()) - { - return visit(ctx->literal()); - } - // Add handling for other unit types as needed return visitChildren(ctx); } \ No newline at end of file diff --git a/Visitor.hpp b/Visitor.hpp index 803be66..3087a8c 100644 --- a/Visitor.hpp +++ b/Visitor.hpp @@ -1,4 +1,6 @@ -#include "HooVisitor.h" +#pragma once + +#include "HooBaseVisitor.h" #include #include @@ -6,7 +8,7 @@ #include #include -class Visitor : public HooVisitor +class Visitor : public HooBaseVisitor { private: std::string &_moduleName;