From 0bcbe1d7d117470cb14a7161959760306e83427e Mon Sep 17 00:00:00 2001 From: CHatingPython Date: Sun, 28 Jun 2026 13:08:15 +0200 Subject: [PATCH] feat(furc): add access specifiers to functions Introduce public and private access specifiers to functions. Closes: #26 --- furc/include/furc/ast/declaration.hpp | 34 ++++++++++++++++--- furc/include/furc/front/token.hpp | 22 +++++++----- furc/src/front/lexer.cpp | 2 ++ furc/src/front/parser.cpp | 49 +++++++++++++++++++++------ 4 files changed, 84 insertions(+), 23 deletions(-) diff --git a/furc/include/furc/ast/declaration.hpp b/furc/include/furc/ast/declaration.hpp index e018d2f..497583c 100644 --- a/furc/include/furc/ast/declaration.hpp +++ b/furc/include/furc/ast/declaration.hpp @@ -26,6 +26,16 @@ private: std::string m_name; }; +enum class declaration_access_t { + Implicit = 0, /**< Implicit access. */ + Public, /**< Public access. */ + Private, /**< Private access. */ +}; + +static inline bool same_access(declaration_access_t lhs, declaration_access_t rhs) { + return lhs == declaration_access_t::Implicit || lhs == rhs; +} + /** * @brief Declaration node type. */ @@ -43,9 +53,10 @@ public: * @brief Construct a new declaration AST node. * * @param location Node location. + * @param access Declaration access. */ - declaration_node(struct location location) - : abstract_node(location) {} + declaration_node(struct location location, declaration_access_t access) + : abstract_node(location), p_access(access) {} public: /** * @brief Returns this node's category. @@ -67,8 +78,17 @@ public: * @return The declaration type. */ virtual declaration_node_t declaration_type() const = 0; + + /** + * @brief Returns the declaration's access. + * + * @return Access. + */ + declaration_access_t access() const { return p_access; } protected: bool equal(const node& rhs) const override; +protected: + declaration_access_t p_access; }; /** @@ -99,11 +119,12 @@ public: */ template function_declaration_node(struct location location, + declaration_access_t access, T&& name, std::optional&& returnType, ParamsFwd&& params, function_declaration_node_t type = function_declaration_node_t::Normal) - : declaration_node(location), + : declaration_node(location, access), p_name(std::forward(name)), p_returnType(std::move(returnType)), p_params(std::forward(params)), @@ -186,11 +207,16 @@ public: */ template function_definition_node(struct location location, + declaration_access_t access, T&& name, std::optional&& type, ParamsFwd&& params, body&& body) - : function_declaration_node(location, std::forward(name), std::move(type), std::forward(params)), + : function_declaration_node(location, + access, + std::forward(name), + std::move(type), + std::forward(params)), m_body(std::move(body)) {} public: /** diff --git a/furc/include/furc/front/token.hpp b/furc/include/furc/front/token.hpp index 35bbc82..d457d74 100644 --- a/furc/include/furc/front/token.hpp +++ b/furc/include/furc/front/token.hpp @@ -147,14 +147,16 @@ static inline std::string operator+(const std::string& str, token_t type) { * @brief Keyword token. */ enum class keyword_token { - None, /**< None */ - Func, /**< `func` */ - Return, /**< `return` */ - If, /**< `if` */ - Else, /**< `else` */ - While, /**< `while` */ - Import, /**< `import` */ - Native, /**< `native` */ + None, /**< None */ + Func, /**< `func` */ + Return, /**< `return` */ + If, /**< `if` */ + Else, /**< `else` */ + While, /**< `while` */ + Import, /**< `import` */ + Native, /**< `native` */ + Public, /**< `public` */ + Private, /**< `private` */ Int32, /**< `int32` */ }; @@ -169,6 +171,8 @@ static inline std::ostream& operator<<(std::ostream& os, keyword_token keyword) case keyword_token::While: return os << "while"; case keyword_token::Import: return os << "import"; case keyword_token::Native: return os << "native"; + case keyword_token::Public: return os << "public"; + case keyword_token::Private: return os << "private"; case keyword_token::Int32: return os << "int32"; } return os; @@ -184,6 +188,8 @@ static inline std::string operator+(const std::string& str, keyword_token keywor case keyword_token::While: return str + "while"; case keyword_token::Import: return str + "import"; case keyword_token::Native: return str + "native"; + case keyword_token::Public: return str + "public"; + case keyword_token::Private: return str + "private"; case keyword_token::Int32: return str + "int32"; } return str; diff --git a/furc/src/front/lexer.cpp b/furc/src/front/lexer.cpp index 420fcc7..8709d7a 100644 --- a/furc/src/front/lexer.cpp +++ b/furc/src/front/lexer.cpp @@ -102,6 +102,8 @@ token_r lexer::next_token() { { "while", keyword_token::While }, { "import", keyword_token::Import }, { "native", keyword_token::Native }, + { "public", keyword_token::Public }, + { "private", keyword_token::Private }, { "int32", keyword_token::Int32 }, }; diff --git a/furc/src/front/parser.cpp b/furc/src/front/parser.cpp index c53379e..fbba3e2 100644 --- a/furc/src/front/parser.cpp +++ b/furc/src/front/parser.cpp @@ -54,21 +54,40 @@ ast::type_r parser::parse_type() { ast::declaration_node_r parser::parse_declaration() { const auto& first = peek_token(); + if (first.has_error()) return ast::declaration_node_r(ast::error{ first.error().location }); switch (first->type) { case token_t::Keyword: { + token firstToken = *first; + + ast::declaration_access_t accessOverride = ast::declaration_access_t::Implicit; + switch ((*first)->keyword) { + default: break; + case keyword_token::Public: + case keyword_token::Private: { + if ((*first)->keyword == keyword_token::Public) accessOverride = ast::declaration_access_t::Public; + if ((*first)->keyword == keyword_token::Private) accessOverride = ast::declaration_access_t::Private; + auto kw = eat_token(token_t::Keyword); + if (kw.has_error()) return ast::declaration_node_r(ast::error{ kw.error().location }); + firstToken = *kw; + } break; + } + ast::function_declaration_node_t funcDeclType{}; - auto first = next_token(); - switch ((*first)->keyword) { + auto kw = next_token(); + if (kw.has_error()) return ast::declaration_node_r(ast::error{ kw.error().location }); + firstToken = *kw; + switch (firstToken->keyword) { case keyword_token::Import: case keyword_token::Native: { - funcDeclType = ((*first)->keyword == keyword_token::Import) ? ast::function_declaration_node_t::Import - : ast::function_declaration_node_t::Native; + funcDeclType = (firstToken->keyword == keyword_token::Import) ? ast::function_declaration_node_t::Import + : ast::function_declaration_node_t::Native; - first = eat_token(token_t::Keyword); - if (first.has_error()) return ast::declaration_node_r(ast::error{ first.error().location }); - if (first->value.keyword != keyword_token::Func) - return ast::declaration_node_r(ast::error{ first->location }); + auto kw = eat_token(token_t::Keyword); + if (kw.has_error()) return ast::declaration_node_r(ast::error{ kw.error().location }); + firstToken = *kw; + if (firstToken.value.keyword != keyword_token::Func) + return ast::declaration_node_r(ast::error{ firstToken.location }); } case keyword_token::Func: { auto name = eat_token(token_t::Identifier); @@ -106,6 +125,12 @@ ast::declaration_node_r parser::parse_declaration() { returnType = *type; } + auto access = (funcDeclType == ast::function_declaration_node_t::Import) + ? ast::declaration_access_t::Private + : accessOverride; + if (access == ast::declaration_access_t::Implicit) access = ast::declaration_access_t::Public; + if (!ast::same_access(accessOverride, access)) return ast::declaration_node_r(ast::error{ tok->location }); + const auto& peek = peek_token(); if (peek.has_error()) return ast::declaration_node_r(ast::error{ peek.error().location }); switch (peek->type) { @@ -114,7 +139,8 @@ ast::declaration_node_r parser::parse_declaration() { if (body.has_error()) return ast::declaration_node_r(ast::error{ body.error().location }); if (funcDeclType != ast::function_declaration_node_t::Normal) return ast::declaration_node_r(ast::error{ body->begin }); - return m_arena->allocate_shared(first->location, + return m_arena->allocate_shared(firstToken.location, + access, name->value.string, std::move(returnType), std::move(params), @@ -122,7 +148,8 @@ ast::declaration_node_r parser::parse_declaration() { } case token_t::Semicolon: { m_peekBuffer.clear(); - return m_arena->allocate_shared(first->location, + return m_arena->allocate_shared(firstToken.location, + access, name->value.string, std::move(returnType), std::move(params), @@ -131,7 +158,7 @@ ast::declaration_node_r parser::parse_declaration() { default: return ast::declaration_node_r(ast::error{ tok->location }); } } - default: return ast::declaration_node_r(ast::error{ first->location }); + default: return ast::declaration_node_r(ast::error{ firstToken.location }); } } case token_t::None: