From d497e2de45f50bdc6ecdb933203784a980077423 Mon Sep 17 00:00:00 2001 From: CHatingPython Date: Wed, 24 Jun 2026 15:50:37 +0200 Subject: [PATCH 1/4] feat: introduce arrow tokens Refs: #16 --- furc/include/furc/front/token.hpp | 7 +++++++ furc/src/front/lexer.cpp | 2 ++ 2 files changed, 9 insertions(+) diff --git a/furc/include/furc/front/token.hpp b/furc/include/furc/front/token.hpp index 386e6c4..ff05de4 100644 --- a/furc/include/furc/front/token.hpp +++ b/furc/include/furc/front/token.hpp @@ -54,6 +54,9 @@ enum class token_t { GreaterThan, /**< `>` */ LessEq, /**< `<=` */ GreaterEq, /**< `>=` */ + + SlimArrow, /**< `->` */ + FatArrow, /**< `=>` */ }; static inline std::ostream& operator<<(std::ostream& os, token_t type) { @@ -92,6 +95,8 @@ static inline std::ostream& operator<<(std::ostream& os, token_t type) { case token_t::GreaterThan: return os << ">"; case token_t::LessEq: return os << "<="; case token_t::GreaterEq: return os << ">="; + case token_t::SlimArrow: return os << "->"; + case token_t::FatArrow: return os << "=>"; } return os; } @@ -132,6 +137,8 @@ static inline std::string operator+(const std::string& str, token_t type) { case token_t::GreaterThan: return str + ">"; case token_t::LessEq: return str + "<="; case token_t::GreaterEq: return str + ">="; + case token_t::SlimArrow: return str + "->"; + case token_t::FatArrow: return str + "=>"; } return str; } diff --git a/furc/src/front/lexer.cpp b/furc/src/front/lexer.cpp index 70007c0..b7adee0 100644 --- a/furc/src/front/lexer.cpp +++ b/furc/src/front/lexer.cpp @@ -144,6 +144,8 @@ token_r lexer::next_token() { { ">", token_t::GreaterThan }, { "<=", token_t::LessEq }, { ">=", token_t::GreaterEq }, + { "->", token_t::SlimArrow }, + { "=>", token_t::FatArrow }, }; token_t type = token_t::None; -- 2.47.3 From a61f5c194b87c2aa73ac3895a6bbdfb21949d237 Mon Sep 17 00:00:00 2001 From: CHatingPython Date: Wed, 24 Jun 2026 15:52:14 +0200 Subject: [PATCH 2/4] refactor(furc): improve function declarations Refs: #16 --- furc/include/furc/ast/declaration.hpp | 23 +++++++++++++++++++---- furc/src/front/parser.cpp | 13 ++++++++++++- furc/src/main.cpp | 2 +- 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/furc/include/furc/ast/declaration.hpp b/furc/include/furc/ast/declaration.hpp index 12d45f2..895b00c 100644 --- a/furc/include/furc/ast/declaration.hpp +++ b/furc/include/furc/ast/declaration.hpp @@ -4,6 +4,7 @@ #include "furc/ast/node.hpp" #include "furc/ast/statement.hpp" +#include #include #include @@ -79,10 +80,11 @@ public: * * @param location Node location. * @param name Name of the function. + * @param type Return type of the function. */ template - function_declaration_node(struct location location, T&& name) - : declaration_node(location), p_name(std::forward(name)) {} + function_declaration_node(struct location location, T&& name, std::optional&& returnType) + : declaration_node(location), p_name(std::forward(name)), p_returnType(std::move(returnType)) {} public: /** * @brief Returns this node's declaration type. @@ -97,6 +99,13 @@ public: * @return Name of the function. */ std::string name() const { return p_name; } + + /** + * @brief Returns function's return type. + * + * @return Function's return type. + */ + const std::optional& return_type() const { return p_returnType; } public: void accept(visitor& visitor) const override; @@ -108,6 +117,11 @@ protected: * @brief Name of the function. */ std::string p_name; + + /** + * @brief Return type of the function. + */ + std::optional p_returnType; }; /** @@ -120,11 +134,12 @@ public: * * @param location Node location. * @param name Name of the function. + * @param type Return type of the function. * @param body Body of the function. */ template - function_definition_node(struct location location, T&& name, body&& body) - : function_declaration_node(location, std::forward(name)), m_body(std::move(body)) {} + function_definition_node(struct location location, T&& name, std::optional&& type, body&& body) + : function_declaration_node(location, std::forward(name), std::move(type)), m_body(std::move(body)) {} public: /** * @brief Returns this node's declaration type. diff --git a/furc/src/front/parser.cpp b/furc/src/front/parser.cpp index a2c18b2..0411c8d 100644 --- a/furc/src/front/parser.cpp +++ b/furc/src/front/parser.cpp @@ -69,6 +69,14 @@ ast::declaration_node_r parser::parse_declaration() { tok = eat_token(token_t::RParen); if (tok.has_error()) return ast::declaration_node_r(ast::error{ tok.error().location }); + std::optional returnType; + if (peek_token().has_value() && peek_token()->type == token_t::SlimArrow) { + auto tok = next_token(); + auto type = parse_type(); + if (type.has_error()) return ast::declaration_node_r(ast::error{ tok->location }); + returnType = *type; + } + const auto& peek = peek_token(); if (peek.has_error()) return ast::declaration_node_r(ast::error{ peek.error().location }); switch (peek->type) { @@ -77,11 +85,14 @@ ast::declaration_node_r parser::parse_declaration() { if (body.has_error()) return ast::declaration_node_r(ast::error{ body.error().location }); return m_arena->allocate_shared(first->location, name->value.string, + std::move(returnType), std::move(body.value())); } case token_t::Semicolon: { m_peekBuffer.clear(); - return m_arena->allocate_shared(first->location, name->value.string); + return m_arena->allocate_shared(first->location, + name->value.string, + std::move(returnType)); } default: return ast::declaration_node_r(ast::error{ tok->location }); } diff --git a/furc/src/main.cpp b/furc/src/main.cpp index 9aef4da..42c678d 100644 --- a/furc/src/main.cpp +++ b/furc/src/main.cpp @@ -13,7 +13,7 @@ int main(void) { try { std::string programStr = R"( - func main() { + func main() -> int32 { x = 0; y = 10; z = 1; -- 2.47.3 From abeb5b390b5f1d816b01750c6e9421688bc2244a Mon Sep 17 00:00:00 2001 From: CHatingPython Date: Wed, 24 Jun 2026 18:06:40 +0200 Subject: [PATCH 3/4] feat(furc): introduce function declaration parameters Closes: #16 --- furc/include/furc/ast/declaration.hpp | 41 +++++++++++++++++++++++---- furc/src/front/parser.cpp | 31 ++++++++++++++++---- 2 files changed, 61 insertions(+), 11 deletions(-) diff --git a/furc/include/furc/ast/declaration.hpp b/furc/include/furc/ast/declaration.hpp index 895b00c..7dd18d4 100644 --- a/furc/include/furc/ast/declaration.hpp +++ b/furc/include/furc/ast/declaration.hpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace furc { namespace ast { @@ -70,6 +71,14 @@ protected: bool equal(const node& rhs) const override; }; +/** + * @brief Parameter of function declaration AST node. + */ +struct function_declaration_param { + std::string name; + type type; +}; + /** * @brief Function declaration AST node. */ @@ -82,9 +91,12 @@ public: * @param name Name of the function. * @param type Return type of the function. */ - template - function_declaration_node(struct location location, T&& name, std::optional&& returnType) - : declaration_node(location), p_name(std::forward(name)), p_returnType(std::move(returnType)) {} + template + function_declaration_node(struct location location, T&& name, std::optional&& returnType, ParamsFwd&& params) + : declaration_node(location), + p_name(std::forward(name)), + p_returnType(std::move(returnType)), + p_params(std::forward(params)) {} public: /** * @brief Returns this node's declaration type. @@ -106,6 +118,13 @@ public: * @return Function's return type. */ const std::optional& return_type() const { return p_returnType; } + + /** + * @brief Returns function's parameters. + * + * @return Function's parameters. + */ + const std::vector& params() const { return p_params; } public: void accept(visitor& visitor) const override; @@ -122,6 +141,11 @@ protected: * @brief Return type of the function. */ std::optional p_returnType; + + /** + * @brief Parameters of the function. + */ + std::vector p_params; }; /** @@ -137,9 +161,14 @@ public: * @param type Return type of the function. * @param body Body of the function. */ - template - function_definition_node(struct location location, T&& name, std::optional&& type, body&& body) - : function_declaration_node(location, std::forward(name), std::move(type)), m_body(std::move(body)) {} + template + function_definition_node(struct location location, + T&& name, + std::optional&& type, + ParamsFwd&& params, + body&& body) + : function_declaration_node(location, std::forward(name), std::move(type), std::forward(params)), + m_body(std::move(body)) {} public: /** * @brief Returns this node's declaration type. diff --git a/furc/src/front/parser.cpp b/furc/src/front/parser.cpp index 0411c8d..4967df5 100644 --- a/furc/src/front/parser.cpp +++ b/furc/src/front/parser.cpp @@ -12,6 +12,7 @@ #include #include #include +#include namespace furc::front { @@ -66,6 +67,25 @@ ast::declaration_node_r parser::parse_declaration() { auto tok = eat_token(token_t::LParen); if (tok.has_error()) return ast::declaration_node_r(ast::error{ tok.error().location }); + + std::vector params; + if (peek_token().has_value() && peek_token()->type != token_t::RParen) { + while (true) { + auto name = eat_token(token_t::Identifier); + if (name.has_error()) return ast::declaration_node_r(ast::error{ name.error().location }); + auto colon = eat_token(token_t::Colon); + if (colon.has_error()) return ast::declaration_node_r(ast::error{ colon.error().location }); + auto type = parse_type(); + if (type.has_error()) return ast::declaration_node_r(ast::error{ type.error().location }); + + params.push_back( + ast::function_declaration_param{ std::string(name->value.string), std::move(*type) }); + + auto comma = eat_token(token_t::Comma); + if (comma.has_error()) break; + } + } + tok = eat_token(token_t::RParen); if (tok.has_error()) return ast::declaration_node_r(ast::error{ tok.error().location }); @@ -86,13 +106,15 @@ ast::declaration_node_r parser::parse_declaration() { return m_arena->allocate_shared(first->location, name->value.string, std::move(returnType), + std::move(params), std::move(body.value())); } case token_t::Semicolon: { m_peekBuffer.clear(); return m_arena->allocate_shared(first->location, name->value.string, - std::move(returnType)); + std::move(returnType), + std::move(params)); } default: return ast::declaration_node_r(ast::error{ tok->location }); } @@ -465,15 +487,14 @@ const token_r& parser::peek_token() { } token_r parser::eat_token(token_t type) { - auto token = next_token(); - if (token.has_error()) return token; - if (token->type != type) { + if (const auto& token = peek_token(); token.has_error() || peek_token()->type != type) { + if (token.has_error()) return token; if (token->type == token_t::None) return token_r(token_error{ token->location, token_error_t::UnexpectedToken, ", expected " + type }); return token_r( token_error{ token->location, token_error_t::UnexpectedToken, ""s + token->type + ", expected " + type }); } - return token; + return next_token(); } } // namespace furc::front -- 2.47.3 From d8d81851d3706ae52f9f1bbc5408f78ecb79fb00 Mon Sep 17 00:00:00 2001 From: CHatingPython Date: Wed, 24 Jun 2026 18:26:01 +0200 Subject: [PATCH 4/4] feat(furc): introduce native and import functions Closes: #19 --- furc/include/furc/ast/declaration.hpp | 31 +++++++++++++++++++++++---- furc/include/furc/front/token.hpp | 6 ++++++ furc/src/front/lexer.cpp | 2 ++ furc/src/front/parser.cpp | 26 ++++++++++++++++------ furc/src/main.cpp | 2 ++ 5 files changed, 56 insertions(+), 11 deletions(-) diff --git a/furc/include/furc/ast/declaration.hpp b/furc/include/furc/ast/declaration.hpp index 7dd18d4..e018d2f 100644 --- a/furc/include/furc/ast/declaration.hpp +++ b/furc/include/furc/ast/declaration.hpp @@ -79,6 +79,12 @@ struct function_declaration_param { type type; }; +enum class function_declaration_node_t { + Normal = 0, + Import, + Native, +}; + /** * @brief Function declaration AST node. */ @@ -92,11 +98,16 @@ public: * @param type Return type of the function. */ template - function_declaration_node(struct location location, T&& name, std::optional&& returnType, ParamsFwd&& params) + function_declaration_node(struct location location, + T&& name, + std::optional&& returnType, + ParamsFwd&& params, + function_declaration_node_t type = function_declaration_node_t::Normal) : declaration_node(location), p_name(std::forward(name)), p_returnType(std::move(returnType)), - p_params(std::forward(params)) {} + p_params(std::forward(params)), + p_type(type) {} public: /** * @brief Returns this node's declaration type. @@ -125,6 +136,13 @@ public: * @return Function's parameters. */ const std::vector& params() const { return p_params; } + + /** + * @brief Returns function's type. + * + * @return Function's type. + */ + function_declaration_node_t type() const { return p_type; } public: void accept(visitor& visitor) const override; @@ -140,12 +158,17 @@ protected: /** * @brief Return type of the function. */ - std::optional p_returnType; + std::optional p_returnType; /** * @brief Parameters of the function. */ std::vector p_params; + + /** + * @brief Type of the function declaration. + */ + function_declaration_node_t p_type; }; /** @@ -164,7 +187,7 @@ public: template function_definition_node(struct location location, T&& name, - std::optional&& type, + std::optional&& type, ParamsFwd&& params, body&& body) : function_declaration_node(location, std::forward(name), std::move(type), std::forward(params)), diff --git a/furc/include/furc/front/token.hpp b/furc/include/furc/front/token.hpp index ff05de4..35bbc82 100644 --- a/furc/include/furc/front/token.hpp +++ b/furc/include/furc/front/token.hpp @@ -153,6 +153,8 @@ enum class keyword_token { If, /**< `if` */ Else, /**< `else` */ While, /**< `while` */ + Import, /**< `import` */ + Native, /**< `native` */ Int32, /**< `int32` */ }; @@ -165,6 +167,8 @@ static inline std::ostream& operator<<(std::ostream& os, keyword_token keyword) case keyword_token::If: return os << "if"; case keyword_token::Else: return os << "else"; case keyword_token::While: return os << "while"; + case keyword_token::Import: return os << "import"; + case keyword_token::Native: return os << "native"; case keyword_token::Int32: return os << "int32"; } return os; @@ -178,6 +182,8 @@ static inline std::string operator+(const std::string& str, keyword_token keywor case keyword_token::If: return str + "if"; case keyword_token::Else: return str + "else"; case keyword_token::While: return str + "while"; + case keyword_token::Import: return str + "import"; + case keyword_token::Native: return str + "native"; case keyword_token::Int32: return str + "int32"; } return str; diff --git a/furc/src/front/lexer.cpp b/furc/src/front/lexer.cpp index b7adee0..420fcc7 100644 --- a/furc/src/front/lexer.cpp +++ b/furc/src/front/lexer.cpp @@ -100,6 +100,8 @@ token_r lexer::next_token() { { "if", keyword_token::If }, { "else", keyword_token::Else }, { "while", keyword_token::While }, + { "import", keyword_token::Import }, + { "native", keyword_token::Native }, { "int32", keyword_token::Int32 }, }; diff --git a/furc/src/front/parser.cpp b/furc/src/front/parser.cpp index 4967df5..c53379e 100644 --- a/furc/src/front/parser.cpp +++ b/furc/src/front/parser.cpp @@ -38,14 +38,11 @@ ast::program_node_r parser::parse() & { while (peek_token().has_value()) { auto decl = parse_declaration(); - if (decl.has_error()) { - program = nullptr; - } else if (program != nullptr) { - program->push(std::move(decl.value())); - } + if (decl.has_error()) return ast::program_node_r(ast::error{ decl.error().location }); + program->push(std::move(decl.value())); } - return program != nullptr ? std::move(program) : ast::program_node_r(ast::error{ location{ m_filename } }); + return program; } ast::type_r parser::parse_type() { @@ -59,8 +56,20 @@ ast::declaration_node_r parser::parse_declaration() { const auto& first = peek_token(); switch (first->type) { case token_t::Keyword: { + ast::function_declaration_node_t funcDeclType{}; + auto first = next_token(); switch ((*first)->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; + + 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 }); + } case keyword_token::Func: { auto name = eat_token(token_t::Identifier); if (name.has_error()) return ast::declaration_node_r(ast::error{ name.error().location }); @@ -103,6 +112,8 @@ ast::declaration_node_r parser::parse_declaration() { case token_t::LBrace: { ast::body_r body = parse_body(); 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, name->value.string, std::move(returnType), @@ -114,7 +125,8 @@ ast::declaration_node_r parser::parse_declaration() { return m_arena->allocate_shared(first->location, name->value.string, std::move(returnType), - std::move(params)); + std::move(params), + funcDeclType); } default: return ast::declaration_node_r(ast::error{ tok->location }); } diff --git a/furc/src/main.cpp b/furc/src/main.cpp index 42c678d..abaac39 100644 --- a/furc/src/main.cpp +++ b/furc/src/main.cpp @@ -13,6 +13,8 @@ int main(void) { try { std::string programStr = R"( + native func print(value: int32); + func main() -> int32 { x = 0; y = 10; -- 2.47.3