diff --git a/furc/include/furc/ast/declaration.hpp b/furc/include/furc/ast/declaration.hpp index 1522e8c..28e69a1 100644 --- a/furc/include/furc/ast/declaration.hpp +++ b/furc/include/furc/ast/declaration.hpp @@ -5,7 +5,6 @@ #include "furc/ast/statement.hpp" #include "furc/front/token.hpp" -#include #include namespace furc { @@ -42,9 +41,7 @@ public: front::token name() const { return m_name; } public: - std::ostream& print(std::ostream& os) const override { - return os << "function " << m_name->string << " declaration"; - } + std::ostream& print(std::ostream& os) const override; protected: front::token m_name; }; @@ -74,16 +71,7 @@ public: const function_body_handle& body() const { return m_body; } public: - std::ostream& print(std::ostream& os) const override { - function_declarartion_node::print(os); - os << ':'; - if (m_body.present()) { - for (const auto& entry : m_body->statements) - os << '\n' << entry; - return os << '\n' << m_body->end << ": " << m_name->string << " end"; - } - return os << m_body.error(); // error - } + std::ostream& print(std::ostream& os) const override; private: function_body_handle m_body; }; diff --git a/furc/include/furc/ast/literal.hpp b/furc/include/furc/ast/literal.hpp index 741c798..d22e12a 100644 --- a/furc/include/furc/ast/literal.hpp +++ b/furc/include/furc/ast/literal.hpp @@ -5,8 +5,6 @@ #include "furc/ast/node.hpp" #include "furc/front/token.hpp" -#include - namespace furc { namespace ast { @@ -50,10 +48,7 @@ public: const handle& value() const { return m_value; } public: - std::ostream& print(std::ostream& os) const override { - if (m_value.has_error()) return os << m_value.error(); - return os << "integer literal (" << *m_value << ")"; - } + std::ostream& print(std::ostream& os) const override; private: handle m_value; }; diff --git a/furc/include/furc/ast/program.hpp b/furc/include/furc/ast/program.hpp index c808978..b1e151b 100644 --- a/furc/include/furc/ast/program.hpp +++ b/furc/include/furc/ast/program.hpp @@ -4,7 +4,6 @@ #include "furc/ast/declaration.hpp" #include "furc/ast/node.hpp" -#include #include namespace furc { @@ -20,13 +19,7 @@ public: const std::vector>& declarations() const { return m_declarations; } public: - std::ostream& print(std::ostream& os) const override { - os << "program:"; - for (const auto& handle : m_declarations) { - os << '\n' << handle; - } - return os; - } + std::ostream& print(std::ostream& os) const override; private: std::vector> m_declarations; }; diff --git a/furc/include/furc/ast/statement.hpp b/furc/include/furc/ast/statement.hpp index 1f4889f..34994fe 100644 --- a/furc/include/furc/ast/statement.hpp +++ b/furc/include/furc/ast/statement.hpp @@ -3,8 +3,6 @@ #include "furc/ast/node.hpp" -#include - namespace furc { namespace ast { @@ -21,13 +19,19 @@ public: virtual statement_node_t statement_type() const = 0; }; +class expression_node; class return_statement_node : public statement_node { public: return_statement_node() = default; + + return_statement_node(node_handle&& value) + : m_value(std::move(value)) {} public: statement_node_t statement_type() const override { return statement_node_t::Return; } - std::ostream& print(std::ostream& os) const override { return os << "return statement"; } + std::ostream& print(std::ostream& os) const override; +private: + node_handle m_value; }; } // namespace ast diff --git a/furc/include/furc/handle.hpp b/furc/include/furc/handle.hpp index d24e8d7..38c26c4 100644 --- a/furc/include/furc/handle.hpp +++ b/furc/include/furc/handle.hpp @@ -105,6 +105,8 @@ class handle { template friend class handle; + friend struct data; + friend std::ostream& operator<<(std::ostream& os, const handle& result); public: using value_type = T; @@ -113,92 +115,151 @@ public: using reference = T&; using const_reference = const T&; public: - template >> - handle(location location, std::shared_ptr value) - : m_location(location), m_value(value) {} + handle() = default; - template >> + template >> + handle(location location, std::shared_ptr value) + : m_data(data(location, value)) {} + + template || std::is_base_of_v>> handle(const handle& other) - : m_location(other.m_location), m_value(std::dynamic_pointer_cast(other.m_value)) {} + : m_data(data{ other }) {} template >> handle(location location, Args&&... args) - : m_location(location), m_value(std::make_shared(std::forward(args)...)) {} + : m_data(data(location, std::forward(args)...)) {} template >> handle(location location, furlang::arena& arena, Args&&... args) - : m_location(location), m_value(arena.allocate_shared(std::forward(args)...)) {} + : m_data(data(location, arena, std::forward(args)...)) {} handle(location location, Error&& error) - : m_location(location), m_error(std::move(error)) {} + : m_data(data(location, std::move(error))) {} template handle(const handle& error) - : m_location(error.location()), m_error(error.error()) {} + : m_data(data(error)) {} ~handle() = default; handle(handle&& other) noexcept - : m_location(other.m_location), m_value(std::move(other.m_value)), m_error(std::move(other.m_error)) { - other.m_value = nullptr; - } + : m_data(std::move(other.m_data)) {} - template || std::is_base_of_v>> - handle(handle&& other) noexcept // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved) - : m_location(other.m_location), m_value(std::move(other.m_value)), m_error(std::move(other.m_error)) { - other.m_value = nullptr; - } + template >> + handle(handle&& other) noexcept + : m_data(data{ std::move(other) }) {} handle(const handle& other) - : m_location(other.m_location), m_value(other.m_value), m_error(other.m_error) {} + : m_data(other.m_data) {} handle& operator=(handle&& other) noexcept { if (this == &other) return *this; - m_location = other.m_location; - m_value = std::move(other.m_value); - m_error = std::move(other.m_error); - other.m_value = nullptr; + m_data = std::move(other.m_data); return *this; } handle& operator=(const handle& other) { if (this == &other) return *this; - m_location = other.m_location; - m_value = other.m_value; - m_error = other.m_error; + m_data = other.m_data; return *this; } public: - location location() const { return m_location; } + location location() const { return m_data->location; } - bool present() const { return m_value != nullptr; } - bool has_error() const { return m_value == nullptr; } + bool present() const { return m_data.has_value() && m_data->value != nullptr; } + bool has_error() const { return m_data.has_value() && m_data->value == nullptr; } - std::shared_ptr shared() { return m_value; } - Error error() const { return m_error; } + std::shared_ptr shared() const { return m_data->value; } + Error error() const { return m_data->error; } - operator reference() { return *m_value; } - operator const_reference() const { return *m_value; } - - reference operator*() { return *m_value; } - const_reference operator*() const { return *m_value; } - pointer operator->() { return m_value.get(); } - const_pointer operator->() const { return m_value.get(); } + reference operator*() { return *m_data->value; } + const_reference operator*() const { return *m_data->value; } + pointer operator->() { return m_data->value.get(); } + const_pointer operator->() const { return m_data->value.get(); } public: friend std::ostream& operator<<(std::ostream& os, const handle& result) { - os << result.m_location << ": "; - if (result.m_value != nullptr) { - os << *result.m_value; + if (!result.m_data.has_value()) return os << "handle empty"; + os << result.m_data->location << ": "; + if (result.m_data->value != nullptr) { + os << *result.m_data->value; } else { - os << "ERROR: " << result.m_error; + os << "ERROR: " << result.m_data->error; } return os; } private: - struct location m_location; - std::shared_ptr m_value = nullptr; - Error m_error; + struct data { + struct location location; + std::shared_ptr value = nullptr; + Error error = {}; + + template >> + data(struct location location, std::shared_ptr value) + : location(location), value(value) {} + + template || std::is_base_of_v>> + data(handle&& other) // NOLINT + : location(other.m_data->location) { + if constexpr (std::is_base_of_v) { + value = std::static_pointer_cast(std::move(other.m_data->value)); + } else { + value = std::dynamic_pointer_cast(std::move(other.m_data->value)); + } + } + + template || std::is_base_of_v>> + data(const handle& other) + : location(other.m_data->location) { + if constexpr (std::is_base_of_v) { + value = std::static_pointer_cast(std::move(other.m_data->value)); + } else { + value = std::dynamic_pointer_cast(std::move(other.m_data->value)); + } + } + + template >> + data(struct location location, Args&&... args) + : location(location), value(std::make_shared(std::forward(args)...)) {} + + template >> + data(struct location location, furlang::arena& arena, Args&&... args) + : location(location), value(arena.allocate_shared(std::forward(args)...)) {} + + data(struct location location, Error&& error) + : location(location), error(std::move(error)) {} + + template + data(const handle& error) + : location(error.location()), error(error.error()) {} + + ~data() = default; + + data(data&& other) noexcept + : location(other.location), value(std::move(other.value)), error(std::move(other.error)) {} + + data(const data& other) + : location(other.location), value(other.value), error(other.error) {} + + data& operator=(data&& other) noexcept { + if (this == &other) return *this; + location = other.location; + value = std::move(other.value); + error = std::move(other.error); + return *this; + } + + data& operator=(const data& other) noexcept { + if (this == &other) return *this; + location = other.location; + value = other.value; + error = other.error; + return *this; + } + }; + std::optional m_data = {}; }; } // namespace furc diff --git a/furc/src/ast.cpp b/furc/src/ast.cpp new file mode 100644 index 0000000..4ccbbd9 --- /dev/null +++ b/furc/src/ast.cpp @@ -0,0 +1,45 @@ +#include "furc/ast/declaration.hpp" +#include "furc/ast/literal.hpp" +#include "furc/ast/node.hpp" +#include "furc/ast/program.hpp" +#include "furc/ast/statement.hpp" + +#include + +namespace furc::ast { + +std::ostream& integer_literal_node::print(std::ostream& os) const { + if (m_value.has_error()) return os << m_value.error(); + return os << "integer literal (" << *m_value << ")"; +} + +std::ostream& function_declarartion_node::print(std::ostream& os) const { + return os << "function " << m_name->string << " declaration"; +} + +std::ostream& function_definition_node::print(std::ostream& os) const { + function_declarartion_node::print(os); + os << ':'; + if (m_body.present()) { + for (const auto& entry : m_body->statements) + os << '\n' << entry; + return os << '\n' << m_body->end << ": " << m_name->string << " end"; + } + return os << m_body.error(); // error +} + +std::ostream& return_statement_node::print(std::ostream& os) const { + os << "return statement"; + if (m_value.present()) return os << " (" << *m_value << ')'; + return os; +} + +std::ostream& program_node::print(std::ostream& os) const { + os << "program:"; + for (const auto& handle : m_declarations) { + os << '\n' << handle; + } + return os; +} + +} // namespace furc::ast \ No newline at end of file diff --git a/furc/src/front/parser.cpp b/furc/src/front/parser.cpp index 4228e76..0a04afb 100644 --- a/furc/src/front/parser.cpp +++ b/furc/src/front/parser.cpp @@ -93,11 +93,16 @@ ast::node_handle parser::parse_statement() { if (tok.has_error()) return tok; switch (tok->type) { case token_t::Keyword: { - next_token(); - auto err = eat_token(token_t::Semicolon); - if (err.has_error()) return err; + auto tok = next_token(); + if (peek_token()->type == token_t::Semicolon) { + next_token(); + return ast::node_handle{ tok.location(), m_arena }; + } - return ast::node_handle{ tok.location(), m_arena }; + auto value = parse_expression(); + auto err = eat_token(token_t::Semicolon); + if (err.has_error()) return err; + return ast::node_handle{ tok.location(), m_arena, std::move(value) }; } default: break; } diff --git a/furc/src/main.cpp b/furc/src/main.cpp index 92b68c4..cf47972 100644 --- a/furc/src/main.cpp +++ b/furc/src/main.cpp @@ -5,7 +5,7 @@ #include int main(void) { - furc::front::parser parser("", "func main() {\n return;\n}"); + furc::front::parser parser("", "func main() {\n return 67;return \"uwu\";\n}"); std::cout << parser.parse() << '\n'; return 0;