diff --git a/furc/include/furc/ast/declaration.hpp b/furc/include/furc/ast/declaration.hpp index 12d45f2..e018d2f 100644 --- a/furc/include/furc/ast/declaration.hpp +++ b/furc/include/furc/ast/declaration.hpp @@ -4,8 +4,10 @@ #include "furc/ast/node.hpp" #include "furc/ast/statement.hpp" +#include #include #include +#include namespace furc { namespace ast { @@ -69,6 +71,20 @@ protected: bool equal(const node& rhs) const override; }; +/** + * @brief Parameter of function declaration AST node. + */ +struct function_declaration_param { + std::string name; + type type; +}; + +enum class function_declaration_node_t { + Normal = 0, + Import, + Native, +}; + /** * @brief Function declaration AST node. */ @@ -79,10 +95,19 @@ 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)) {} + template + 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_type(type) {} public: /** * @brief Returns this node's declaration type. @@ -97,6 +122,27 @@ 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; } + + /** + * @brief Returns function's parameters. + * + * @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; @@ -108,6 +154,21 @@ protected: * @brief Name of the function. */ std::string p_name; + + /** + * @brief Return type of the function. + */ + 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; }; /** @@ -120,11 +181,17 @@ 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)) {} + 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/include/furc/front/token.hpp b/furc/include/furc/front/token.hpp index 386e6c4..35bbc82 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; } @@ -146,6 +153,8 @@ enum class keyword_token { If, /**< `if` */ Else, /**< `else` */ While, /**< `while` */ + Import, /**< `import` */ + Native, /**< `native` */ Int32, /**< `int32` */ }; @@ -158,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; @@ -171,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 70007c0..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 }, }; @@ -144,6 +146,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; diff --git a/furc/src/front/parser.cpp b/furc/src/front/parser.cpp index a2c18b2..c53379e 100644 --- a/furc/src/front/parser.cpp +++ b/furc/src/front/parser.cpp @@ -12,6 +12,7 @@ #include #include #include +#include namespace furc::front { @@ -37,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() { @@ -58,30 +56,77 @@ 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 }); 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 }); + 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) { 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), + std::move(params), 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), + std::move(params), + funcDeclType); } default: return ast::declaration_node_r(ast::error{ tok->location }); } @@ -454,15 +499,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 diff --git a/furc/src/main.cpp b/furc/src/main.cpp index 9aef4da..abaac39 100644 --- a/furc/src/main.cpp +++ b/furc/src/main.cpp @@ -13,7 +13,9 @@ int main(void) { try { std::string programStr = R"( - func main() { + native func print(value: int32); + + func main() -> int32 { x = 0; y = 10; z = 1;