forked from KPGPMC/furlang
refactor(AST): improve literals
Changed literal node to templated class and literals to aliases.
This commit is contained in:
@@ -4,6 +4,7 @@
|
|||||||
#include "furc/diag.hpp"
|
#include "furc/diag.hpp"
|
||||||
#include "furlang/result.hpp"
|
#include "furlang/result.hpp"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -56,14 +57,6 @@ class node;
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
using node_r = furlang::result<std::shared_ptr<T>, error>;
|
using node_r = furlang::result<std::shared_ptr<T>, error>;
|
||||||
|
|
||||||
class literal_node;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Alias for handle to literal_node.
|
|
||||||
* @see literal_node
|
|
||||||
*/
|
|
||||||
using literal_node_r = node_r<literal_node>;
|
|
||||||
|
|
||||||
class expression_node;
|
class expression_node;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -96,7 +89,21 @@ class program_node;
|
|||||||
*/
|
*/
|
||||||
using program_node_r = node_r<program_node>;
|
using program_node_r = node_r<program_node>;
|
||||||
|
|
||||||
class string_literal_node;
|
/**
|
||||||
|
* @brief Literal node type.
|
||||||
|
*/
|
||||||
|
enum class literal_node_t {
|
||||||
|
String, /**< String literal. */
|
||||||
|
Integer, /**< Integer literal. */
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename, literal_node_t>
|
||||||
|
class literal_node;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief String literal AST node.
|
||||||
|
*/
|
||||||
|
using string_literal_node = literal_node<std::string, literal_node_t::String>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Alias for handle to string_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<string_literal_node>;
|
using string_literal_node_r = node_r<string_literal_node>;
|
||||||
|
|
||||||
class integer_literal_node;
|
/**
|
||||||
|
* @brief Integer literal AST node.
|
||||||
|
*/
|
||||||
|
using integer_literal_node = literal_node<std::uint64_t, literal_node_t::Integer>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Alias for handle to integer_literal_node.
|
* @brief Alias for handle to integer_literal_node.
|
||||||
|
|||||||
@@ -1,33 +1,58 @@
|
|||||||
|
// NOLINTBEGIN(portability-template-virtual-member-function)
|
||||||
|
|
||||||
#ifndef FURC_AST_LITERAL_HPP
|
#ifndef FURC_AST_LITERAL_HPP
|
||||||
#define FURC_AST_LITERAL_HPP
|
#define FURC_AST_LITERAL_HPP
|
||||||
|
|
||||||
#include "furc/ast/expression.hpp"
|
#include "furc/ast/expression.hpp"
|
||||||
#include "furc/ast/node.hpp"
|
#include "furc/ast/node.hpp"
|
||||||
#include "furc/front/token.hpp"
|
|
||||||
|
|
||||||
namespace furc {
|
namespace furc {
|
||||||
namespace ast {
|
namespace ast {
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Literal node type.
|
|
||||||
*/
|
|
||||||
enum class literal_node_t {
|
|
||||||
String, /**< String literal. */
|
|
||||||
Integer, /**< Integer literal. */
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Literal AST node.
|
* @brief Literal AST node.
|
||||||
*/
|
*/
|
||||||
|
template <typename ValueType, literal_node_t LiteralType>
|
||||||
class literal_node : public expression_node {
|
class literal_node : public expression_node {
|
||||||
|
public:
|
||||||
|
using value_type = std::remove_reference_t<ValueType>; /**< Value type. */
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Construct a new literal AST node.
|
* @brief Construct a new literal AST node.
|
||||||
*
|
*
|
||||||
* @param location Node location.
|
* @param location Node location.
|
||||||
*/
|
*/
|
||||||
|
template <typename = std::enable_if_t<std::is_default_constructible_v<ValueType>>>
|
||||||
literal_node(struct location location)
|
literal_node(struct location location)
|
||||||
: expression_node(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 <typename... Args, typename = std::enable_if_t<std::is_constructible_v<ValueType, Args...>>>
|
||||||
|
literal_node(struct location location, Args&&... args)
|
||||||
|
: expression_node(location), p_value(std::forward<Args>(args)...) {}
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Returns this node's category.
|
* @brief Returns this node's category.
|
||||||
@@ -48,98 +73,30 @@ public:
|
|||||||
*
|
*
|
||||||
* @return The literal type.
|
* @return The literal type.
|
||||||
*/
|
*/
|
||||||
virtual literal_node_t literal_type() const = 0;
|
literal_node_t literal_type() const { return LiteralType; }
|
||||||
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<std::string_view, error>; /**< 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; }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns this node's value.
|
* @brief Returns this node's value.
|
||||||
*
|
*
|
||||||
* @return A string view result.
|
* @return A string view result.
|
||||||
*/
|
*/
|
||||||
const value_type& value() const { return m_value; }
|
const value_type& value() const { return p_value; }
|
||||||
public:
|
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:
|
protected:
|
||||||
bool equal(const node& rhs) const override;
|
bool equal(const node& rhsNode) const override {
|
||||||
private:
|
const auto& rhs = dynamic_cast<const literal_node&>(rhsNode);
|
||||||
value_type m_value;
|
return literal_type() == rhs.literal_type() && p_value == rhs.p_value;
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Integer literal AST node.
|
|
||||||
*/
|
|
||||||
class integer_literal_node final : public literal_node {
|
|
||||||
public:
|
|
||||||
using value_type = furlang::result<front::integer_token, error>; /**< 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;
|
|
||||||
protected:
|
protected:
|
||||||
bool equal(const node& rhs) const override;
|
value_type p_value; /**< Node value. */
|
||||||
private:
|
|
||||||
value_type m_value;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ast
|
} // namespace ast
|
||||||
} // namespace furc
|
} // namespace furc
|
||||||
|
|
||||||
#endif // FURC_AST_LITERAL_HPP
|
#endif // FURC_AST_LITERAL_HPP
|
||||||
|
|
||||||
|
// NOLINTEND(portability-template-virtual-member-function)
|
||||||
@@ -59,7 +59,6 @@ private:
|
|||||||
ast::declaration_node_r parse_declaration();
|
ast::declaration_node_r parse_declaration();
|
||||||
ast::statement_node_r parse_statement();
|
ast::statement_node_r parse_statement();
|
||||||
ast::expression_node_r parse_expression(std::uint32_t precedence = 16);
|
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_primary();
|
||||||
ast::expression_node_r parse_expression_unary(std::uint32_t precedence);
|
ast::expression_node_r parse_expression_unary(std::uint32_t precedence);
|
||||||
|
|||||||
+1
-31
@@ -1,5 +1,5 @@
|
|||||||
#include "furc/ast/declaration.hpp"
|
#include "furc/ast/declaration.hpp"
|
||||||
#include "furc/ast/literal.hpp"
|
#include "furc/ast/expression.hpp"
|
||||||
#include "furc/ast/node.hpp"
|
#include "furc/ast/node.hpp"
|
||||||
#include "furc/ast/program.hpp"
|
#include "furc/ast/program.hpp"
|
||||||
#include "furc/ast/statement.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";
|
return os << error.location << ": ERROR: unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool literal_node::equal(const node& rhs) const {
|
|
||||||
return literal_type() == dynamic_cast<const literal_node&>(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<const string_literal_node&>(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<const integer_literal_node&>(rhs).m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool expression_node::equal(const node& rhs) const {
|
bool expression_node::equal(const node& rhs) const {
|
||||||
return expression_type() == dynamic_cast<const expression_node&>(rhs).expression_type();
|
return expression_type() == dynamic_cast<const expression_node&>(rhs).expression_type();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,12 +72,12 @@ void ir_generator::visit(const ast::compound_statement_node& node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ir_generator::visit(const ast::string_literal_node& node) {
|
void ir_generator::visit(const ast::string_literal_node& node) {
|
||||||
push<furlang::ir::assign_instruction>(ir::operand::new_string(std::string(*node.value())),
|
push<furlang::ir::assign_instruction>(ir::operand::new_string(node.value()),
|
||||||
ir::operand::new_reg(m_registerCounter++));
|
ir::operand::new_reg(m_registerCounter++));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ir_generator::visit(const ast::integer_literal_node& node) {
|
void ir_generator::visit(const ast::integer_literal_node& node) {
|
||||||
push<furlang::ir::assign_instruction>(ir::operand::new_integer(*node.value()),
|
push<furlang::ir::assign_instruction>(ir::operand::new_integer(node.value()),
|
||||||
ir::operand::new_reg(m_registerCounter++));
|
ir::operand::new_reg(m_registerCounter++));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+10
-21
@@ -160,25 +160,6 @@ ast::expression_node_r parser::parse_expression(std::uint32_t precedence) {
|
|||||||
return parse_expression_rhs(parse_expression_unary(precedence), 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<ast::string_literal_node>(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<ast::integer_literal_node>(tok->location, (*tok)->integer);
|
|
||||||
}
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ast::literal_node_r(ast::error{ tok->location });
|
|
||||||
}
|
|
||||||
|
|
||||||
ast::expression_node_r parser::parse_expression_primary() {
|
ast::expression_node_r parser::parse_expression_primary() {
|
||||||
const auto& tok = peek_token();
|
const auto& tok = peek_token();
|
||||||
switch (tok->type) {
|
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 });
|
if (err.has_error()) return ast::expression_node_r(ast::error{ err.error().location });
|
||||||
return node;
|
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<ast::string_literal_node>(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<ast::integer_literal_node>(tok->location, (*tok)->integer);
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
auto literal = parse_literal();
|
|
||||||
if (literal.has_value()) return std::move(*literal);
|
|
||||||
return ast::expression_node_r(ast::error{ tok->location });
|
return ast::expression_node_r(ast::error{ tok->location });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user