diff --git a/furc/include/furc/ast/fwd.hpp b/furc/include/furc/ast/fwd.hpp index 796cb4e..e985a94 100644 --- a/furc/include/furc/ast/fwd.hpp +++ b/furc/include/furc/ast/fwd.hpp @@ -4,6 +4,7 @@ #include "furc/diag.hpp" #include "furlang/result.hpp" +#include #include #include @@ -56,14 +57,6 @@ class node; template using node_r = furlang::result, error>; -class literal_node; - -/** - * @brief Alias for handle to literal_node. - * @see literal_node - */ -using literal_node_r = node_r; - class expression_node; /** @@ -96,7 +89,21 @@ class program_node; */ using program_node_r = node_r; -class string_literal_node; +/** + * @brief Literal node type. + */ +enum class literal_node_t { + String, /**< String literal. */ + Integer, /**< Integer literal. */ +}; + +template +class literal_node; + +/** + * @brief String literal AST node. + */ +using string_literal_node = literal_node; /** * @brief Alias for handle to string_literal_node. @@ -104,7 +111,10 @@ class string_literal_node; */ using string_literal_node_r = node_r; -class integer_literal_node; +/** + * @brief Integer literal AST node. + */ +using integer_literal_node = literal_node; /** * @brief Alias for handle to integer_literal_node. diff --git a/furc/include/furc/ast/literal.hpp b/furc/include/furc/ast/literal.hpp index 81cad76..2a08c88 100644 --- a/furc/include/furc/ast/literal.hpp +++ b/furc/include/furc/ast/literal.hpp @@ -1,33 +1,58 @@ +// NOLINTBEGIN(portability-template-virtual-member-function) + #ifndef FURC_AST_LITERAL_HPP #define FURC_AST_LITERAL_HPP #include "furc/ast/expression.hpp" #include "furc/ast/node.hpp" -#include "furc/front/token.hpp" namespace furc { namespace ast { -/** - * @brief Literal node type. - */ -enum class literal_node_t { - String, /**< String literal. */ - Integer, /**< Integer literal. */ -}; - /** * @brief Literal AST node. */ +template class literal_node : public expression_node { +public: + using value_type = std::remove_reference_t; /**< Value type. */ public: /** * @brief Construct a new literal AST node. * * @param location Node location. */ + template >> literal_node(struct location location) : expression_node(location) {} + + /** + * @brief Construct a new literal AST node. + * + * @param location Node location. + * @param value Node value to copy. + */ + literal_node(struct location location, const value_type& value) + : expression_node(location), p_value(value) {} + + /** + * @brief Construct a new literal AST node. + * + * @param location Node location. + * @param value Node value to move. + */ + literal_node(struct location location, value_type&& value) + : expression_node(location), p_value(std::move(value)) {} + + /** + * @brief Construct a new literal AST node. + * + * @param location Node location. + * @param args Arguments to call value constructor with. + */ + template >> + literal_node(struct location location, Args&&... args) + : expression_node(location), p_value(std::forward(args)...) {} public: /** * @brief Returns this node's category. @@ -48,98 +73,30 @@ public: * * @return The literal type. */ - virtual literal_node_t literal_type() const = 0; -protected: - bool equal(const node& rhs) const override; -}; - -/** - * @brief String literal AST node. - */ -class string_literal_node final : public literal_node { -public: - using value_type = furlang::result; /**< Value type. */ -public: - /** - * @brief Construct a new string literal node object from a handle. - * - * @param location Node location. - * @param value A string view result. - */ - string_literal_node(struct location location, value_type&& value) - : literal_node(location), m_value(std::move(value)) {} -public: - /** - * @brief Returns this node's literal type. - * - * @return literal_node_t::String. - */ - literal_node_t literal_type() const override { return literal_node_t::String; } + literal_node_t literal_type() const { return LiteralType; } /** * @brief Returns this node's value. * * @return A string view result. */ - const value_type& value() const { return m_value; } + const value_type& value() const { return p_value; } public: - void accept(visitor& visitor) const override; + void accept(visitor& visitor) const override { visitor.visit(*this); } - std::ostream& print(std::ostream& os) const override; + std::ostream& print(std::ostream& os) const override { return os << p_value; } protected: - bool equal(const node& rhs) const override; -private: - value_type m_value; -}; - -/** - * @brief Integer literal AST node. - */ -class integer_literal_node final : public literal_node { -public: - using value_type = furlang::result; /**< Value type. */ -public: - /** - * @brief Construct a new integer literal node object from a handle. - * - * @param location Node location. - * @param value An integer result. - */ - integer_literal_node(struct location location, value_type&& value) - : literal_node(location), m_value(std::move(value)) {} -public: - /** - * @brief Returns this node's literal type. - * - * @return literal_node_t::Integer. - */ - literal_node_t literal_type() const override { return literal_node_t::Integer; } - - /** - * @brief Returns this node's value. - * - * @return An integer result. - */ - const value_type& value() const { return m_value; } - - /** - * @brief Compares this node with an integer token for equality. - * - * @param integer Integer token to compare against. - * @return true if the integer token is equal to this node. - */ - bool operator==(front::integer_token integer) const { return m_value == integer; } -public: - void accept(visitor& visitor) const override; - - std::ostream& print(std::ostream& os) const override; + bool equal(const node& rhsNode) const override { + const auto& rhs = dynamic_cast(rhsNode); + return literal_type() == rhs.literal_type() && p_value == rhs.p_value; + } protected: - bool equal(const node& rhs) const override; -private: - value_type m_value; + value_type p_value; /**< Node value. */ }; } // namespace ast } // namespace furc -#endif // FURC_AST_LITERAL_HPP \ No newline at end of file +#endif // FURC_AST_LITERAL_HPP + +// NOLINTEND(portability-template-virtual-member-function) \ No newline at end of file diff --git a/furc/include/furc/front/parser.hpp b/furc/include/furc/front/parser.hpp index d55ecd9..0390051 100644 --- a/furc/include/furc/front/parser.hpp +++ b/furc/include/furc/front/parser.hpp @@ -59,7 +59,6 @@ private: ast::declaration_node_r parse_declaration(); ast::statement_node_r parse_statement(); ast::expression_node_r parse_expression(std::uint32_t precedence = 16); - ast::literal_node_r parse_literal(); ast::expression_node_r parse_expression_primary(); ast::expression_node_r parse_expression_unary(std::uint32_t precedence); diff --git a/furc/src/ast.cpp b/furc/src/ast.cpp index 6ea9333..cfba539 100644 --- a/furc/src/ast.cpp +++ b/furc/src/ast.cpp @@ -1,5 +1,5 @@ #include "furc/ast/declaration.hpp" -#include "furc/ast/literal.hpp" +#include "furc/ast/expression.hpp" #include "furc/ast/node.hpp" #include "furc/ast/program.hpp" #include "furc/ast/statement.hpp" @@ -12,36 +12,6 @@ std::ostream& operator<<(std::ostream& os, const error& error) { return os << error.location << ": ERROR: unknown"; } -bool literal_node::equal(const node& rhs) const { - return literal_type() == dynamic_cast(rhs).literal_type(); -} - -void string_literal_node::accept(visitor& visitor) const { - visitor.visit(*this); -} - -std::ostream& string_literal_node::print(std::ostream& os) const { - if (m_value.has_error()) return os << m_value.error(); - return os << '"' << *m_value << '"'; -} - -bool string_literal_node::equal(const node& rhs) const { - return literal_node::equal(rhs) && m_value == dynamic_cast(rhs).m_value; -} - -void integer_literal_node::accept(visitor& visitor) const { - visitor.visit(*this); -} - -std::ostream& integer_literal_node::print(std::ostream& os) const { - if (m_value.has_error()) return os << m_value.error(); - return os << *m_value; -} - -bool integer_literal_node::equal(const node& rhs) const { - return literal_node::equal(rhs) && m_value == dynamic_cast(rhs).m_value; -} - bool expression_node::equal(const node& rhs) const { return expression_type() == dynamic_cast(rhs).expression_type(); } diff --git a/furc/src/front/ir_generator.cpp b/furc/src/front/ir_generator.cpp index bbdad4a..a256200 100644 --- a/furc/src/front/ir_generator.cpp +++ b/furc/src/front/ir_generator.cpp @@ -72,12 +72,12 @@ void ir_generator::visit(const ast::compound_statement_node& node) { } void ir_generator::visit(const ast::string_literal_node& node) { - push(ir::operand::new_string(std::string(*node.value())), + push(ir::operand::new_string(node.value()), ir::operand::new_reg(m_registerCounter++)); } void ir_generator::visit(const ast::integer_literal_node& node) { - push(ir::operand::new_integer(*node.value()), + push(ir::operand::new_integer(node.value()), ir::operand::new_reg(m_registerCounter++)); } diff --git a/furc/src/front/parser.cpp b/furc/src/front/parser.cpp index 02f9311..9506e1c 100644 --- a/furc/src/front/parser.cpp +++ b/furc/src/front/parser.cpp @@ -160,25 +160,6 @@ ast::expression_node_r parser::parse_expression(std::uint32_t precedence) { return parse_expression_rhs(parse_expression_unary(precedence), precedence); } -ast::literal_node_r parser::parse_literal() { - const auto& tok = peek_token(); - switch (tok->type) { - case token_t::String: { - auto tok = next_token(); - if (tok.has_error()) return ast::literal_node_r(ast::error{ tok.error().location }); - return m_arena.allocate_shared(tok->location, (*tok)->string); - } - case token_t::Integer: { - auto tok = next_token(); - if (tok.has_error()) return ast::literal_node_r(ast::error{ tok.error().location }); - return m_arena.allocate_shared(tok->location, (*tok)->integer); - } - default: break; - } - - return ast::literal_node_r(ast::error{ tok->location }); -} - ast::expression_node_r parser::parse_expression_primary() { const auto& tok = peek_token(); switch (tok->type) { @@ -194,9 +175,17 @@ ast::expression_node_r parser::parse_expression_primary() { if (err.has_error()) return ast::expression_node_r(ast::error{ err.error().location }); return node; } + case token_t::String: { + auto tok = next_token(); + if (tok.has_error()) return ast::expression_node_r(ast::error{ tok.error().location }); + return m_arena.allocate_shared(tok->location, (*tok)->string); + } + case token_t::Integer: { + auto tok = next_token(); + if (tok.has_error()) return ast::expression_node_r(ast::error{ tok.error().location }); + return m_arena.allocate_shared(tok->location, (*tok)->integer); + } default: { - auto literal = parse_literal(); - if (literal.has_value()) return std::move(*literal); return ast::expression_node_r(ast::error{ tok->location }); } }