Add gtest

Signed-off-by: CHatingPython <chatingpython@gmail.com>
This commit is contained in:
CHatingPython
2026-05-25 08:16:44 +02:00
committed by CHatingPython
parent 7df35fc075
commit 438288f8f1
8 changed files with 81 additions and 41 deletions
+2
View File
@@ -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)
+14 -3
View File
@@ -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/)
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)
+23 -32
View File
@@ -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;
}
}
+4 -2
View File
@@ -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 << ": ";
+4 -1
View File
@@ -1,10 +1,13 @@
#include "furc/front/lexer.hpp"
#include <cctype>
#include <string>
#include <unordered_map>
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)) + "'" };
}
}
}
-2
View File
@@ -64,7 +64,6 @@ ast::node_handle<ast::declaration_node> parser::parse_declaration() {
return ast::node_handle<ast::function_declarartion_node>{ 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<ast::declaration_node> parser::parse_declaration() {
}
}
case token_t::None:
case token_t::Error:
case token_t::Identifier:
case token_t::Integer:
case token_t::Lparen:
+5 -1
View File
@@ -1,3 +1,5 @@
#ifndef LIBFURC
#include "furc/front/parser.hpp"
#include <iostream>
@@ -7,4 +9,6 @@ int main(void) {
std::cout << parser.parse() << '\n';
return 0;
}
}
#endif // LIBFURC
+29
View File
@@ -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("<TEMP>", "()\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