From 438288f8f19a39b9dab2097a02607be1cadccfe7 Mon Sep 17 00:00:00 2001 From: CHatingPython Date: Mon, 25 May 2026 08:16:44 +0200 Subject: [PATCH] Add gtest Signed-off-by: CHatingPython --- CMakeLists.txt | 2 ++ furc/CMakeLists.txt | 17 ++++++++-- furc/include/furc/front/token.hpp | 55 +++++++++++++------------------ furc/include/furc/handle.hpp | 6 ++-- furc/src/front/lexer.cpp | 5 ++- furc/src/front/parser.cpp | 2 -- furc/src/main.cpp | 6 +++- furc/test/lexer.cpp | 29 ++++++++++++++++ 8 files changed, 81 insertions(+), 41 deletions(-) create mode 100644 furc/test/lexer.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 68a378f..42362d9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,5 +2,7 @@ cmake_minimum_required(VERSION 3.14) project(furlang VERSION 0.0.0 LANGUAGES CXX) +find_package(GTest REQUIRED) + add_subdirectory(furlang) add_subdirectory(furc) \ No newline at end of file diff --git a/furc/CMakeLists.txt b/furc/CMakeLists.txt index 35c8ae3..ce04753 100644 --- a/furc/CMakeLists.txt +++ b/furc/CMakeLists.txt @@ -1,4 +1,15 @@ file(GLOB_RECURSE FURC_SRCS "src/**.cpp") -file(GLOB_RECURSE FURC_HDRS "src/**.cpp") -add_executable(furc ${FURC_SRCS} ${FURC_HDRS}) -target_include_directories(furc PRIVATE include/) \ No newline at end of file +file(GLOB_RECURSE FURC_HDRS "include/**.hpp") +add_library(libfurc ${FURC_SRCS} ${FURC_HDRS}) +target_include_directories(libfurc PUBLIC include/) +target_compile_definitions(libfurc PRIVATE LIBFURC) +set_target_properties(libfurc PROPERTIES PREFIX "") +add_executable(furc src/main.cpp) +target_link_libraries(furc PRIVATE libfurc) + +include(GoogleTest) + +file(GLOB_RECURSE FURC_TESTS "test/**.cpp") +add_executable(furc_tests ${FURC_TESTS}) +target_link_libraries(furc_tests PRIVATE libfurc GTest::gtest_main) +gtest_discover_tests(furc_tests) \ No newline at end of file diff --git a/furc/include/furc/front/token.hpp b/furc/include/furc/front/token.hpp index 964df07..1740702 100644 --- a/furc/include/furc/front/token.hpp +++ b/furc/include/furc/front/token.hpp @@ -12,7 +12,6 @@ namespace front { enum class token_t { None, - Error, Identifier, Keyword, Integer, @@ -28,14 +27,9 @@ enum class token_t { Dot, }; -static inline bool is_token_type_empty(token_t type) { - return type == token_t::None || type == token_t::Error; -} - static inline std::ostream& operator<<(std::ostream& os, token_t type) { switch (type) { case token_t::None: return os << "none"; - case token_t::Error: return os << "error"; case token_t::Identifier: return os << "identifier"; case token_t::Keyword: return os << "keyword"; case token_t::Integer: return os << "integer"; @@ -55,7 +49,6 @@ static inline std::ostream& operator<<(std::ostream& os, token_t type) { static inline std::string operator+(const std::string& str, token_t type) { switch (type) { case token_t::None: return str + "none"; - case token_t::Error: return str + "error"; case token_t::Identifier: return str + "identifier"; case token_t::Keyword: return str + "keyword"; case token_t::Integer: return str + "integer"; @@ -72,18 +65,6 @@ static inline std::string operator+(const std::string& str, token_t type) { } } -enum class error_token { - None, - UnexpectedCharacter, -}; - -static inline std::ostream& operator<<(std::ostream& os, error_token error) { - switch (error) { - case error_token::None: return os << "none"; - case error_token::UnexpectedCharacter: return os << "unexpected character"; - } -} - enum class keyword_token { None, Func, @@ -108,7 +89,6 @@ static inline std::string operator+(const std::string& str, keyword_token keywor struct token { token_t type = token_t::None; - error_token error = error_token::None; keyword_token keyword = keyword_token::None; std::string_view value; @@ -117,25 +97,36 @@ struct token { token(token_t type, std::string_view value = {}) : type(type), value(value) {} - token(error_token error, std::string_view value = {}) - : type(token_t::Error), error(error), value(value) {} - token(keyword_token keyword, std::string_view value = {}) : type(token_t::Keyword), keyword(keyword), value(value) {} + + bool operator==(const token& rhs) const { + if (type != rhs.type) return false; + switch (type) { + case token_t::None: + case token_t::Identifier: return value == rhs.value; + case token_t::Keyword: return keyword == rhs.keyword; + case token_t::Integer: return value == rhs.value; + case token_t::Lparen: + case token_t::Rparen: + case token_t::Lbrace: + case token_t::Rbrace: + case token_t::Lbracket: + case token_t::Rbracket: + case token_t::Semicolon: + case token_t::Colon: + case token_t::Comma: + case token_t::Dot: return true; + } + } }; static inline std::ostream& operator<<(std::ostream& os, const token& token) { - os << token.type; switch (token.type) { - case token_t::Error: { - os << ": " << token.error; - if (!token.value.empty()) os << " \"" << token.value << '"'; - return os; - } case token_t::Identifier: - case token_t::Keyword: - case token_t::Integer: return os << ": " << token.value; - default: return os; + case token_t::Integer: return os << token.value; + case token_t::Keyword: return os << token.keyword; + default: return os << token.type; } } diff --git a/furc/include/furc/handle.hpp b/furc/include/furc/handle.hpp index 9cb831e..db7d550 100644 --- a/furc/include/furc/handle.hpp +++ b/furc/include/furc/handle.hpp @@ -76,10 +76,12 @@ public: operator const_reference() const { return *m_value; } operator Error() const { return m_error; } - reference operator*() { return m_value; } - const_reference operator*() const { return m_value; } + reference operator*() { return *m_value; } + const_reference operator*() const { return *m_value; } pointer operator->() { return &*m_value; } const_pointer operator->() const { return &*m_value; } +public: + bool operator==(const T& rhs) const { return m_value.has_value() && *m_value == rhs; } public: friend std::ostream& operator<<(std::ostream& os, const handle& result) { os << result.m_location << ": "; diff --git a/furc/src/front/lexer.cpp b/furc/src/front/lexer.cpp index 5c547f2..f846964 100644 --- a/furc/src/front/lexer.cpp +++ b/furc/src/front/lexer.cpp @@ -1,10 +1,13 @@ #include "furc/front/lexer.hpp" #include +#include #include namespace furc::front { +using namespace std::string_literals; + lexer::lexer(std::string_view filename, std::string_view content) : m_filename(filename), m_content(content) {} @@ -45,7 +48,7 @@ token_handle<> lexer::next_token() { return { location, token_t::Identifier, value }; } - return { location, error_token::UnexpectedCharacter, m_content.substr(m_cursor, 1) }; + return { location, "unexpected character '"s.append(m_content.substr(m_cursor, 1)) + "'" }; } } } diff --git a/furc/src/front/parser.cpp b/furc/src/front/parser.cpp index ccab912..5c8ebfd 100644 --- a/furc/src/front/parser.cpp +++ b/furc/src/front/parser.cpp @@ -64,7 +64,6 @@ ast::node_handle parser::parse_declaration() { return ast::node_handle{ first.location(), name }; } case token_t::None: - case token_t::Error: case token_t::Identifier: case token_t::Keyword: case token_t::Integer: @@ -84,7 +83,6 @@ ast::node_handle parser::parse_declaration() { } } case token_t::None: - case token_t::Error: case token_t::Identifier: case token_t::Integer: case token_t::Lparen: diff --git a/furc/src/main.cpp b/furc/src/main.cpp index 33330c2..92b68c4 100644 --- a/furc/src/main.cpp +++ b/furc/src/main.cpp @@ -1,3 +1,5 @@ +#ifndef LIBFURC + #include "furc/front/parser.hpp" #include @@ -7,4 +9,6 @@ int main(void) { std::cout << parser.parse() << '\n'; return 0; -} \ No newline at end of file +} + +#endif // LIBFURC \ No newline at end of file diff --git a/furc/test/lexer.cpp b/furc/test/lexer.cpp new file mode 100644 index 0000000..f134553 --- /dev/null +++ b/furc/test/lexer.cpp @@ -0,0 +1,29 @@ +#include "furc/front/lexer.hpp" + +#include "gtest/gtest.h" + +namespace { + +using namespace furc::front; +using namespace std::string_view_literals; + +#define EXPECT_TOKEN(lexer, t) EXPECT_EQ((lexer).next_token(), (t)); + +TEST(Lexer, Tokens) { + lexer lexer("", "()\n\t\t{\n}[]; :,.main return func"); + EXPECT_TOKEN(lexer, (token{ token_t::Lparen, "("sv })); + EXPECT_TOKEN(lexer, (token{ token_t::Rparen, ")"sv })); + EXPECT_TOKEN(lexer, (token{ token_t::Lbrace, "{"sv })); + EXPECT_TOKEN(lexer, (token{ token_t::Rbrace, "}"sv })); + EXPECT_TOKEN(lexer, (token{ token_t::Lbracket, "["sv })); + EXPECT_TOKEN(lexer, (token{ token_t::Rbracket, "]"sv })); + EXPECT_TOKEN(lexer, (token{ token_t::Semicolon, ";"sv })); + EXPECT_TOKEN(lexer, (token{ token_t::Colon, ":"sv })); + EXPECT_TOKEN(lexer, (token{ token_t::Comma, ","sv })); + EXPECT_TOKEN(lexer, (token{ token_t::Dot, "."sv })); + EXPECT_TOKEN(lexer, (token{ token_t::Identifier, "main"sv })); + EXPECT_TOKEN(lexer, (token{ keyword_token::Return })); + EXPECT_TOKEN(lexer, (token{ keyword_token::Func })); +} + +} // namespace \ No newline at end of file