diff --git a/furc/include/furc/ast/declaration.hpp b/furc/include/furc/ast/declaration.hpp index 5f0146d..470dd38 100644 --- a/furc/include/furc/ast/declaration.hpp +++ b/furc/include/furc/ast/declaration.hpp @@ -19,7 +19,15 @@ enum class declaration_node_t { /** * @brief Declaration AST node interface. */ -class declaration_node : public statement_node { +class declaration_node : public statement_node, public abstract_node { +public: + /** + * @brief Construct a new declaration AST node. + * + * @param location Node location. + */ + declaration_node(struct location location) + : abstract_node(location) {} public: /** * @brief Returns this node's category. @@ -53,10 +61,11 @@ public: /** * @brief Construct a new function declaration node object from name token. * + * @param location Node location. * @param name Name of the function. */ - function_declaration_node(front::token name) - : p_name(name) {} + function_declaration_node(struct location location, front::token name) + : declaration_node(location), p_name(name) {} public: /** * @brief Returns this node's declaration type. @@ -92,11 +101,12 @@ public: /** * @brief Construct a new function definition node object from name and body. * + * @param location Node location. * @param name Name of the function. * @param body Body of the function. */ - function_definition_node(front::token name, body_r&& body) - : function_declaration_node(name), m_body(std::move(body)) {} + function_definition_node(struct location location, front::token name, body_r&& body) + : function_declaration_node(location, name), m_body(std::move(body)) {} public: /** * @brief Returns this node's declaration type. diff --git a/furc/include/furc/ast/expression.hpp b/furc/include/furc/ast/expression.hpp index bde9b9a..15f3c16 100644 --- a/furc/include/furc/ast/expression.hpp +++ b/furc/include/furc/ast/expression.hpp @@ -21,7 +21,15 @@ enum class expression_node_t { /** * @brief Expression AST node. */ -class expression_node : public statement_node { +class expression_node : public statement_node, public abstract_node { +public: + /** + * @brief Construct a new expression AST node. + * + * @param location Node location. + */ + expression_node(struct location location) + : abstract_node(location) {} public: /** * @brief Returns this node's category. @@ -57,10 +65,11 @@ public: /** * @brief Construct a new var read expression node object from a name handle. * + * @param location Node location. * @param name Handle to the name. */ - var_read_expression_node(name_type&& name) - : m_name(std::move(name)) {} + var_read_expression_node(struct location location, name_type&& name) + : expression_node(location), m_name(std::move(name)) {} /** * @brief Returns the variable's name. @@ -114,11 +123,12 @@ public: /** * @brief Construct a new unaryop expression node object from type and expression node handle. * + * @param location Node location. * @param type Operation type. * @param node Handle to the inner expression node. */ - unaryop_expression_node(unaryop_expression_node_t type, expression_node_r&& node) - : m_type(type), m_node(std::move(node)) {} + unaryop_expression_node(struct location location, unaryop_expression_node_t type, expression_node_r&& node) + : expression_node(location), m_type(type), m_node(std::move(node)) {} /** * @brief Sets this node's inner expression. @@ -199,12 +209,16 @@ public: /** * @brief Construct a new binary operation expression AST node. * + * @param location Node location. * @param type Binary operation type. * @param lhs Left-hand-side expression. * @param rhs Right-hand-side expression. */ - binop_expression_node(binop_expression_node_t type, expression_node_r&& lhs, expression_node_r&& rhs) - : m_type(type), m_lhs(std::move(lhs)), m_rhs(std::move(rhs)) {} + binop_expression_node(struct location location, + binop_expression_node_t type, + expression_node_r&& lhs, + expression_node_r&& rhs) + : expression_node(location), m_type(type), m_lhs(std::move(lhs)), m_rhs(std::move(rhs)) {} /** * @brief Returns this node's binary operation type. @@ -276,21 +290,29 @@ public: /** * @brief Construct a new variable assignment expression AST node. * + * @param location Node location. * @param lhs Left-hand-side expression handle. * @param rhs Right-hand-side expression handle. */ - var_assign_expression_node(expression_node_r&& lhs, expression_node_r&& rhs) - : m_compound(binop_expression_node_t::None), m_lhs(std::move(lhs)), m_rhs(std::move(rhs)) {} + var_assign_expression_node(struct location location, expression_node_r&& lhs, expression_node_r&& rhs) + : expression_node(location), + m_compound(binop_expression_node_t::None), + m_lhs(std::move(lhs)), + m_rhs(std::move(rhs)) {} /** * @brief Construct a new compound variable assignment expression AST node. * + * @param location Node location. * @param compound Compound operation type. * @param lhs Left-hand-side expression handle. * @param rhs Right-hand-side expression handle. */ - var_assign_expression_node(binop_expression_node_t compound, expression_node_r&& lhs, expression_node_r&& rhs) - : m_compound(compound), m_lhs(std::move(lhs)), m_rhs(std::move(rhs)) {} + var_assign_expression_node(struct location location, + binop_expression_node_t compound, + expression_node_r&& lhs, + expression_node_r&& rhs) + : expression_node(location), m_compound(compound), m_lhs(std::move(lhs)), m_rhs(std::move(rhs)) {} /** * @brief Returns this node's compound operation type. diff --git a/furc/include/furc/ast/literal.hpp b/furc/include/furc/ast/literal.hpp index c45474a..81cad76 100644 --- a/furc/include/furc/ast/literal.hpp +++ b/furc/include/furc/ast/literal.hpp @@ -20,6 +20,14 @@ enum class literal_node_t { * @brief Literal AST node. */ class literal_node : public expression_node { +public: + /** + * @brief Construct a new literal AST node. + * + * @param location Node location. + */ + literal_node(struct location location) + : expression_node(location) {} public: /** * @brief Returns this node's category. @@ -55,10 +63,11 @@ 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(value_type&& value) - : m_value(std::move(value)) {} + 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. @@ -93,10 +102,11 @@ public: /** * @brief Construct a new integer literal node object from a handle. * + * @param location Node location. * @param value An integer result. */ - integer_literal_node(value_type&& value) - : m_value(std::move(value)) {} + 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. diff --git a/furc/include/furc/ast/node.hpp b/furc/include/furc/ast/node.hpp index 9a50947..1219a95 100644 --- a/furc/include/furc/ast/node.hpp +++ b/furc/include/furc/ast/node.hpp @@ -71,6 +71,14 @@ public: * @return The node category. */ virtual node_t category() const = 0; + + /** + * @brief Returns the location of this AST node. + * @see locaiton + * + * @return The location. + */ + virtual location location() const = 0; public: /** * @brief Compares two nodes for equality. @@ -128,6 +136,28 @@ protected: virtual bool equal(const node& rhs) const = 0; }; +/** + * @brief An abstract AST node. + * @see node + * + * Implements location(). + */ +class abstract_node : public virtual node { +public: + abstract_node(struct location location) + : p_location(location) {} +public: + /** + * @brief Returns the location of this AST node. + * @see locaiton + * + * @return The location. + */ + struct location location() const override { return p_location; } +protected: + struct location p_location; /**< Node location. */ +}; + } // namespace ast } // namespace furc diff --git a/furc/include/furc/ast/program.hpp b/furc/include/furc/ast/program.hpp index f636162..878c685 100644 --- a/furc/include/furc/ast/program.hpp +++ b/furc/include/furc/ast/program.hpp @@ -12,9 +12,15 @@ namespace ast { /** * @brief Program AST node. */ -class program_node final : public node { +class program_node final : public abstract_node { public: - program_node() = default; + /** + * @brief Construct a new program AST node. + * + * @param location Node location. + */ + program_node(struct location location) + : abstract_node(location) {} node_t category() const override { return node_t::Program; } public: diff --git a/furc/include/furc/ast/statement.hpp b/furc/include/furc/ast/statement.hpp index d85d545..afb1da9 100644 --- a/furc/include/furc/ast/statement.hpp +++ b/furc/include/furc/ast/statement.hpp @@ -22,7 +22,7 @@ enum class statement_node_t { /** * @brief Statement AST node. */ -class statement_node : public node { +class statement_node : public virtual node { public: /** * @brief Returns this node's category. @@ -44,19 +44,24 @@ protected: /** * @brief Return statement AST node. */ -class return_statement_node final : public statement_node { +class return_statement_node final : public statement_node, public abstract_node { public: using value_type = std::optional; /**< Value type. */ public: - return_statement_node() = default; + /** + * @brief Construct a new return statement AST node. + */ + return_statement_node(struct location location) + : abstract_node(location) {} /** * @brief Construct a new return statement AST node. * + * @param location Node location. * @param value Return value handle. */ - return_statement_node(expression_node_r&& value) - : m_value(std::move(value)) {} + return_statement_node(struct location location, expression_node_r&& value) + : abstract_node(location), m_value(std::move(value)) {} public: /** * @brief Returns this node's return value handle. @@ -84,26 +89,31 @@ private: /** * @brief If statement AST node. */ -class if_statement_node final : public statement_node { +class if_statement_node final : public statement_node, public abstract_node { public: /** * @brief Construct a new if statement AST node. * + * @param location Node location. * @param cond Condition expression handle. * @param then Then statement handle. */ - if_statement_node(expression_node_r&& cond, statement_node_r&& then) - : m_cond(std::move(cond)), m_then(std::move(then)) {} + if_statement_node(struct location location, expression_node_r&& cond, statement_node_r&& then) + : abstract_node(location), m_cond(std::move(cond)), m_then(std::move(then)) {} /** * @brief Construct a new if statement AST node. * + * @param location Node location. * @param cond Condition expression handle. * @param then Then statement handle. * @param elze Else statement handle. */ - if_statement_node(expression_node_r&& cond, statement_node_r&& then, statement_node_r&& elze) - : m_cond(std::move(cond)), m_then(std::move(then)), m_else(std::move(elze)) {} + if_statement_node(struct location location, + expression_node_r&& cond, + statement_node_r&& then, + statement_node_r&& elze) + : abstract_node(location), m_cond(std::move(cond)), m_then(std::move(then)), m_else(std::move(elze)) {} public: /** * @brief Returns this node's condition expression handle. @@ -147,15 +157,16 @@ private: /** * @brief Compound statement AST node. */ -class compound_statement_node final : public statement_node { +class compound_statement_node final : public statement_node, public abstract_node { public: /** * @brief Construct a new compound statement AST node. * + * @param location Node location. * @param body Body handle. */ - compound_statement_node(body_r&& body) - : m_body(std::move(body)) {} + compound_statement_node(struct location location, body_r&& body) + : abstract_node(location), m_body(std::move(body)) {} public: /** * @brief Returns this node's body handle. diff --git a/furc/src/ast.cpp b/furc/src/ast.cpp index 34f91c2..6ea9333 100644 --- a/furc/src/ast.cpp +++ b/furc/src/ast.cpp @@ -13,7 +13,7 @@ std::ostream& operator<<(std::ostream& os, const error& error) { } bool literal_node::equal(const node& rhs) const { - return literal_type() == reinterpret_cast(rhs).literal_type(); + return literal_type() == dynamic_cast(rhs).literal_type(); } void string_literal_node::accept(visitor& visitor) const { @@ -26,7 +26,7 @@ std::ostream& string_literal_node::print(std::ostream& os) const { } bool string_literal_node::equal(const node& rhs) const { - return literal_node::equal(rhs) && m_value == reinterpret_cast(rhs).m_value; + return literal_node::equal(rhs) && m_value == dynamic_cast(rhs).m_value; } void integer_literal_node::accept(visitor& visitor) const { @@ -39,11 +39,11 @@ std::ostream& integer_literal_node::print(std::ostream& os) const { } bool integer_literal_node::equal(const node& rhs) const { - return literal_node::equal(rhs) && m_value == reinterpret_cast(rhs).m_value; + return literal_node::equal(rhs) && m_value == dynamic_cast(rhs).m_value; } bool expression_node::equal(const node& rhs) const { - return expression_type() == reinterpret_cast(rhs).expression_type(); + return expression_type() == dynamic_cast(rhs).expression_type(); } void var_read_expression_node::accept(visitor& visitor) const { @@ -56,7 +56,7 @@ std::ostream& var_read_expression_node::print(std::ostream& os) const { } bool var_read_expression_node::equal(const node& rhsNode) const { - const auto& rhs = reinterpret_cast(rhsNode); + const auto& rhs = dynamic_cast(rhsNode); return expression_node::equal(rhsNode) && m_name == rhs.m_name; } @@ -90,7 +90,7 @@ std::ostream& unaryop_expression_node::print(std::ostream& os) const { } bool unaryop_expression_node::equal(const node& rhsNode) const { - const auto& rhs = reinterpret_cast(rhsNode); + const auto& rhs = dynamic_cast(rhsNode); return expression_node::equal(rhsNode) && m_type == rhs.m_type && m_node == rhs.m_node; } @@ -122,7 +122,7 @@ std::ostream& binop_expression_node::print(std::ostream& os) const { } bool binop_expression_node::equal(const node& rhsNode) const { - const auto& rhs = reinterpret_cast(rhsNode); + const auto& rhs = dynamic_cast(rhsNode); return expression_node::equal(rhsNode) && m_type == rhs.m_type && m_lhs == rhs.m_lhs && m_rhs == rhs.m_rhs; } @@ -135,12 +135,12 @@ std::ostream& var_assign_expression_node::print(std::ostream& os) const { } bool var_assign_expression_node::equal(const node& rhsNode) const { - const auto& rhs = reinterpret_cast(rhsNode); + const auto& rhs = dynamic_cast(rhsNode); return expression_node::equal(rhsNode) && m_compound == rhs.m_compound && m_lhs == rhs.m_lhs && m_rhs == rhs.m_rhs; } bool declaration_node::equal(const node& rhs) const { - return declaration_type() == reinterpret_cast(rhs).declaration_type(); + return declaration_type() == dynamic_cast(rhs).declaration_type(); } void function_declaration_node::accept(visitor& visitor) const { @@ -152,7 +152,7 @@ std::ostream& function_declaration_node::print(std::ostream& os) const { } bool function_declaration_node::equal(const node& rhs) const { - return declaration_node::equal(rhs) && p_name == reinterpret_cast(rhs).p_name; + return declaration_node::equal(rhs) && p_name == dynamic_cast(rhs).p_name; } void function_definition_node::accept(visitor& visitor) const { @@ -171,12 +171,11 @@ std::ostream& function_definition_node::print(std::ostream& os) const { } bool function_definition_node::equal(const node& rhs) const { - return function_declaration_node::equal(rhs) && - m_body == reinterpret_cast(rhs).m_body; + return function_declaration_node::equal(rhs) && m_body == dynamic_cast(rhs).m_body; } bool statement_node::equal(const node& rhs) const { - return statement_type() == reinterpret_cast(rhs).statement_type(); + return statement_type() == dynamic_cast(rhs).statement_type(); } void return_statement_node::accept(visitor& visitor) const { @@ -190,7 +189,7 @@ std::ostream& return_statement_node::print(std::ostream& os) const { } bool return_statement_node::equal(const node& rhs) const { - return statement_node::equal(rhs) && m_value == reinterpret_cast(rhs).m_value; + return statement_node::equal(rhs) && m_value == dynamic_cast(rhs).m_value; } void if_statement_node::accept(visitor& visitor) const { @@ -205,7 +204,7 @@ std::ostream& if_statement_node::print(std::ostream& os) const { } bool if_statement_node::equal(const node& rhsNode) const { - const auto& rhs = reinterpret_cast(rhsNode); + const auto& rhs = dynamic_cast(rhsNode); return statement_node::equal(rhs) && m_cond == rhs.m_cond && m_then == rhs.m_then && m_else == rhs.m_else; } @@ -218,7 +217,7 @@ std::ostream& compound_statement_node::print(std::ostream& os) const { } bool compound_statement_node::equal(const node& rhs) const { - return statement_node::equal(rhs) && m_body == reinterpret_cast(rhs).m_body; + return statement_node::equal(rhs) && m_body == dynamic_cast(rhs).m_body; } void program_node::accept(visitor& visitor) const { @@ -240,7 +239,7 @@ std::ostream& program_node::print(std::ostream& os) const { } bool program_node::equal(const node& rhs) const { - return m_declarations == reinterpret_cast(rhs).m_declarations; + return m_declarations == dynamic_cast(rhs).m_declarations; } std::ostream& operator<<(std::ostream& os, const body& body) { diff --git a/furc/src/front/parser.cpp b/furc/src/front/parser.cpp index d9bc105..02f9311 100644 --- a/furc/src/front/parser.cpp +++ b/furc/src/front/parser.cpp @@ -31,7 +31,7 @@ parser::parser(std::string_view filename) } ast::program_node_r parser::parse() & { - auto program = m_arena.allocate_shared(); + auto program = m_arena.allocate_shared(location{ m_filename }); while (peek_token().has_value()) { program->push(std::move(parse_declaration())); @@ -61,11 +61,11 @@ 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 }); - return m_arena.allocate_shared(*name, std::move(body)); + return m_arena.allocate_shared(first->location, *name, std::move(body)); } case token_t::Semicolon: { m_peekBuffer.clear(); - return m_arena.allocate_shared(*name); + return m_arena.allocate_shared(first->location, *name); } default: return ast::declaration_node_r(ast::error{ tok->location }); } @@ -101,13 +101,13 @@ ast::statement_node_r parser::parse_statement() { auto tok = next_token(); if (peek_token()->type == token_t::Semicolon) { next_token(); - return m_arena.allocate_shared(); + return m_arena.allocate_shared(location); } auto value = parse_expression(); auto err = eat_token(token_t::Semicolon); if (err.has_error()) return ast::statement_node_r(ast::error{ err.error().location }); - return m_arena.allocate_shared(std::move(value)); + return m_arena.allocate_shared(location, std::move(value)); } case keyword_token::If: { auto tok = next_token(); @@ -126,19 +126,20 @@ ast::statement_node_r parser::parse_statement() { peek_token()->value.keyword == keyword_token::Else) { next_token(); - return m_arena.allocate_shared(std::move(cond), + return m_arena.allocate_shared(location, + std::move(cond), std::move(then), std::move(parse_statement())); } - return m_arena.allocate_shared(std::move(cond), std::move(then)); + return m_arena.allocate_shared(location, std::move(cond), std::move(then)); } case keyword_token::None: case keyword_token::Func: default: break; } } - case token_t::LBrace: return m_arena.allocate_shared(parse_body()); + case token_t::LBrace: return m_arena.allocate_shared(location, parse_body()); default: break; } @@ -165,12 +166,12 @@ ast::literal_node_r parser::parse_literal() { 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)->string); + 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)->integer); + return m_arena.allocate_shared(tok->location, (*tok)->integer); } default: break; } @@ -184,7 +185,7 @@ ast::expression_node_r parser::parse_expression_primary() { case token_t::Identifier: { auto tok = next_token(); if (tok.has_error()) return ast::expression_node_r(ast::error{ tok.error().location }); - return m_arena.allocate_shared((*tok)->string); + return m_arena.allocate_shared(tok->location, (*tok)->string); } case token_t::LParen: { auto tok = next_token(); @@ -230,7 +231,8 @@ ast::expression_node_r parser::parse_expression_unary(std::uint32_t precedence) expression = parse_expression_unary(current.precedence + 1); } - result = m_arena.allocate_shared(current.type, std::move(expression)); + result = + m_arena.allocate_shared(token->location, current.type, std::move(expression)); } if (result == nullptr) return parse_expression_primary(); @@ -341,13 +343,18 @@ ast::expression_node_r parser::parse_expression_rhs(ast::expression_node_r&& ini switch (current.type) { case rhsop_info_t::Unaryop: - lhs = m_arena.allocate_shared(current.unary, std::move(lhs)); + lhs = + m_arena.allocate_shared(opToken->location, current.unary, std::move(lhs)); break; case rhsop_info_t::Binop: - lhs = m_arena.allocate_shared(current.binary, std::move(lhs), std::move(rhs)); + lhs = m_arena.allocate_shared(opToken->location, + current.binary, + std::move(lhs), + std::move(rhs)); break; case rhsop_info_t::Assignment: - lhs = m_arena.allocate_shared(current.assignment, + lhs = m_arena.allocate_shared(opToken->location, + current.assignment, std::move(lhs), std::move(rhs)); break;