From 224468446d948cdbffaf2ee10d58ad563e83b1f9 Mon Sep 17 00:00:00 2001 From: CHatingPython Date: Tue, 4 Aug 2026 12:51:47 +0200 Subject: [PATCH] refactor: remove furc for later remake --- furas/src/gen.cpp | 10 +- furc/include/furc/ast/declaration.hpp | 248 --------- furc/include/furc/ast/expression.hpp | 409 -------------- furc/include/furc/ast/fwd.hpp | 259 --------- furc/include/furc/ast/literal.hpp | 102 ---- furc/include/furc/ast/node.hpp | 166 ------ furc/include/furc/ast/program.hpp | 52 -- furc/include/furc/ast/statement.hpp | 244 --------- furc/include/furc/ast/visitor.hpp | 152 ------ furc/include/furc/back/furvm.hpp | 43 -- furc/include/furc/diag.hpp | 42 -- furc/include/furc/front/ir_generator.hpp | 61 --- furc/include/furc/front/lexer.hpp | 70 --- furc/include/furc/front/parser.hpp | 86 --- furc/include/furc/front/post_process.hpp | 41 -- furc/include/furc/front/token.hpp | 412 -------------- furc/src/ast.cpp | 251 --------- furc/src/back/furvm.cpp | 196 ------- furc/src/front/ir_generator.cpp | 232 -------- furc/src/front/lexer.cpp | 200 ------- furc/src/front/parser.cpp | 587 -------------------- furc/src/front/post_process.cpp | 605 --------------------- furc/src/main.cpp | 86 +-- furc/test/lexer.cpp | 75 +-- furc/test/parser.cpp | 274 ---------- furlang/include/furlang/ir/instruction.hpp | 13 +- furvm/include/furvm/context.hpp | 2 +- furvm/include/furvm/executor.hpp | 2 +- furvm/include/furvm/module.hpp | 30 +- furvm/include/furvm/thing.hpp | 71 ++- furvm/src/executor.cpp | 63 ++- 31 files changed, 95 insertions(+), 4989 deletions(-) delete mode 100644 furc/include/furc/ast/declaration.hpp delete mode 100644 furc/include/furc/ast/expression.hpp delete mode 100644 furc/include/furc/ast/fwd.hpp delete mode 100644 furc/include/furc/ast/literal.hpp delete mode 100644 furc/include/furc/ast/node.hpp delete mode 100644 furc/include/furc/ast/program.hpp delete mode 100644 furc/include/furc/ast/statement.hpp delete mode 100644 furc/include/furc/ast/visitor.hpp delete mode 100644 furc/include/furc/back/furvm.hpp delete mode 100644 furc/include/furc/diag.hpp delete mode 100644 furc/include/furc/front/ir_generator.hpp delete mode 100644 furc/include/furc/front/lexer.hpp delete mode 100644 furc/include/furc/front/parser.hpp delete mode 100644 furc/include/furc/front/post_process.hpp delete mode 100644 furc/include/furc/front/token.hpp delete mode 100644 furc/src/ast.cpp delete mode 100644 furc/src/back/furvm.cpp delete mode 100644 furc/src/front/ir_generator.cpp delete mode 100644 furc/src/front/lexer.cpp delete mode 100644 furc/src/front/parser.cpp delete mode 100644 furc/src/front/post_process.cpp delete mode 100644 furc/test/parser.cpp diff --git a/furas/src/gen.cpp b/furas/src/gen.cpp index 6044b68..c39aa9d 100644 --- a/furas/src/gen.cpp +++ b/furas/src/gen.cpp @@ -145,10 +145,10 @@ struct mod_context { struct token_result { generator_error error; - token token; + token value; - struct token* operator->() { return &token; } - struct token& operator*() { return token; } + token* operator->() { return &value; } + token& operator*() { return value; } bool operator!() const { return error.type != generator_error::Success; } }; @@ -180,12 +180,12 @@ struct mod_context { static token_result eat_token(lexer& lexer, enum token::type type) { auto token = next_token(lexer); if (!token) return token; - if (token.token.type != type) { + if (token.value.type != type) { return { { generator_error::UnexpectedToken, "Expected "s + token_type(type) + ", but got " + token_type(token->type) }, { token::Count } }; } - return { { generator_error::Success }, token.token }; + return { { generator_error::Success }, token.value }; } generator_error generate(lexer& lexer) { diff --git a/furc/include/furc/ast/declaration.hpp b/furc/include/furc/ast/declaration.hpp deleted file mode 100644 index 497583c..0000000 --- a/furc/include/furc/ast/declaration.hpp +++ /dev/null @@ -1,248 +0,0 @@ -#ifndef FURC_AST_DECLARATION_HPP -#define FURC_AST_DECLARATION_HPP - -#include "furc/ast/node.hpp" -#include "furc/ast/statement.hpp" - -#include -#include -#include -#include - -namespace furc { -namespace ast { - -/** - * @brief Type class for AST declarations. - */ -class type { -public: - template >> - type(NameFwd&& name) - : m_name(std::forward(name)) {} -public: - const std::string& name() const { return m_name; } -private: - std::string m_name; -}; - -enum class declaration_access_t { - Implicit = 0, /**< Implicit access. */ - Public, /**< Public access. */ - Private, /**< Private access. */ -}; - -static inline bool same_access(declaration_access_t lhs, declaration_access_t rhs) { - return lhs == declaration_access_t::Implicit || lhs == rhs; -} - -/** - * @brief Declaration node type. - */ -enum class declaration_node_t { - Func, /**< Function declaration. */ - FuncDef, /**< Function definition. */ -}; - -/** - * @brief Declaration AST node interface. - */ -class declaration_node : public statement_node, public abstract_node { -public: - /** - * @brief Construct a new declaration AST node. - * - * @param location Node location. - * @param access Declaration access. - */ - declaration_node(struct location location, declaration_access_t access) - : abstract_node(location), p_access(access) {} -public: - /** - * @brief Returns this node's category. - * - * @return node_t::Declaration. - */ - node_t category() const override { return node_t::Declaration; } - - /** - * @brief Returns this node's statement type. - * - * @return statement_node_t::Declaration. - */ - statement_node_t statement_type() const final { return statement_node_t::Declaration; } - - /** - * @brief Returns this node's declaration type. - * - * @return The declaration type. - */ - virtual declaration_node_t declaration_type() const = 0; - - /** - * @brief Returns the declaration's access. - * - * @return Access. - */ - declaration_access_t access() const { return p_access; } -protected: - bool equal(const node& rhs) const override; -protected: - declaration_access_t p_access; -}; - -/** - * @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. - */ -class function_declaration_node : public declaration_node { -public: - /** - * @brief Construct a new function declaration node object from name token. - * - * @param location Node location. - * @param name Name of the function. - * @param type Return type of the function. - */ - template - function_declaration_node(struct location location, - declaration_access_t access, - T&& name, - std::optional&& returnType, - ParamsFwd&& params, - function_declaration_node_t type = function_declaration_node_t::Normal) - : declaration_node(location, access), - 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. - * - * @return declaration_node_t::FunctionDeclaration. - */ - declaration_node_t declaration_type() const override { return declaration_node_t::Func; } - - /** - * @brief Returns function's name. - * - * @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; - - std::ostream& print(std::ostream& os) const override; -protected: - bool equal(const node& rhs) const override; -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; -}; - -/** - * @brief Function definition AST node. - */ -class function_definition_node final : public function_declaration_node { -public: - /** - * @brief Construct a new function definition node object from name and body. - * - * @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, - declaration_access_t access, - T&& name, - std::optional&& type, - ParamsFwd&& params, - body&& body) - : function_declaration_node(location, - access, - std::forward(name), - std::move(type), - std::forward(params)), - m_body(std::move(body)) {} -public: - /** - * @brief Returns this node's declaration type. - * - * @return declaration_node_t::FunctionDefinition. - */ - declaration_node_t declaration_type() const override { return declaration_node_t::FuncDef; } - - /** - * @brief Returns function's body. - * - * @return Body of the function. - */ - const body& body() const { return m_body; } -public: - void accept(visitor& visitor) const override; - - std::ostream& print(std::ostream& os) const override; -protected: - bool equal(const node& rhs) const override; -private: - struct body m_body; -}; - -} // namespace ast -} // namespace furc - -#endif // FURC_AST_DECLARATION_HPP diff --git a/furc/include/furc/ast/expression.hpp b/furc/include/furc/ast/expression.hpp deleted file mode 100644 index 73b9109..0000000 --- a/furc/include/furc/ast/expression.hpp +++ /dev/null @@ -1,409 +0,0 @@ -#ifndef FURC_AST_EXPRESSION_HPP -#define FURC_AST_EXPRESSION_HPP - -#include "furc/ast/node.hpp" -#include "furc/ast/statement.hpp" - -#include - -namespace furc { -namespace ast { - -/** - * @brief Expression node type. - */ -enum class expression_node_t { - Literal, /**< Literal */ - VarRead, /**< Variable read expression */ - Unaryop, /**< Unary operation expression */ - Binop, /**< Binary operation expression */ - VarAssign, /**< Variable assignment expression */ - FuncCall, /**< Function call expression. */ -}; - -/** - * @brief Expression AST 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. - * - * @return node_t::Expression. - */ - node_t category() const override { return node_t::Expression; } - - /** - * @brief Returns this node's statement type. - * - * @return statement_node_t::Expression. - */ - statement_node_t statement_type() const override { return statement_node_t::Expression; } - - /** - * @brief Returns this node's expression type. - * - * @return The expression type. - */ - virtual expression_node_t expression_type() const = 0; -protected: - bool equal(const node& rhs) const override; -}; - -/** - * @brief Var read expression AST node. - */ -class var_read_expression_node final : public expression_node { -public: - /** - * @brief Construct a new var read expression node object from a name handle. - * - * @param location Node location. - * @param name Handle to the name. - */ - template - var_read_expression_node(struct location location, T&& name) - : expression_node(location), m_name(std::forward(name)) {} - - /** - * @brief Returns the variable's name. - * - * @return Name of the variable. - */ - const std::string& get_name() const { return m_name; } - - /** - * @brief Returns the variable's name. - * - * @return Name of the variable. - */ - std::string&& move_name() { return std::move(m_name); } -public: - /** - * @brief Returns this node's expression type. - * - * @return expression_node_t::VarRead. - */ - expression_node_t expression_type() const override { return expression_node_t::VarRead; } -public: - void accept(visitor& visitor) const override; - - std::ostream& print(std::ostream& os) const override; -protected: - bool equal(const node& rhs) const override; -private: - std::string m_name; -}; - -/** - * @brief Unary operation node type. - */ -enum class unaryop_expression_node_t { - Positive, /**< Positive (unary plus) */ - Negative, /**< Negative (unary minus) */ - PrefixIncrement, /**< Prefix increment */ - PostfixIncrement, /**< Postfix increment */ - PrefixDecrement, /**< Prefix decrement */ - PostfixDecrement, /**< Postfix decrement */ - Pointerof, /**< Pointerof */ - Sizeof, /**< Sizeof */ -}; - -/** - * @brief Unary operation expression AST node. - */ -class unary_op_expression_node final : public expression_node { -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. - */ - unary_op_expression_node(struct location location, unaryop_expression_node_t type, expression_node_p&& node) - : expression_node(location), m_type(type), m_node(std::move(node)) {} - - /** - * @brief Sets this node's inner expression. - * - * @param node New node handle. - */ - void set_node(expression_node_p&& node) { m_node = std::move(node); } - - /** - * @brief Returns the type of this node's operation. - * - * @return The operation type. - */ - unaryop_expression_node_t type() const { return m_type; } - - /** - * @brief Returns this node's inner expression. - * - * @return The inner expression. - */ - const expression_node_p& get_node() const { return m_node; } - - /** - * @brief Returns this node's inner expression. - * - * @return The inner expression. - */ - expression_node_p& get_node() { return m_node; } - - /** - * @brief Moves this node's inner expression. - * - * @return The moved inner expression. - */ - expression_node_p&& move_node() { return std::move(m_node); } -public: - /** - * @brief Returns this node's expression type. - * - * @return expression_node_t::Unaryop. - */ - expression_node_t expression_type() const override { return expression_node_t::Unaryop; } -public: - void accept(visitor& visitor) const override; - - std::ostream& print(std::ostream& os) const override; -protected: - bool equal(const node& rhs) const override; -private: - unaryop_expression_node_t m_type; - expression_node_p m_node; /**< The inner expression. */ -}; - -/** - * @brief Binary operation expression node type. - */ -enum class binop_expression_node_t { - None = 0, /**< None */ - Add, /**< Addition */ - Sub, /**< Subtraction */ - Mul, /**< Multiplication */ - Div, /**< Division */ - Mod, /**< Modulo */ - - Equal, /**< Equality */ - NotEqual, /**< Inequality */ - LessThan, /**< Less */ - GreaterThan, /**< Greater */ - LessEqual, /**< Less or equal */ - GreaterEqual, /**< Greater or equal */ -}; - -/** - * @brief Binary operation expression AST node. - */ -class binary_op_expression_node final : public expression_node { -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. - */ - binary_op_expression_node(struct location location, - binop_expression_node_t type, - expression_node_p&& lhs, - expression_node_p&& 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. - * - * @return The binary operation type. - */ - binop_expression_node_t type() const { return m_type; }; - - /** - * @brief Returns this node's left-hand-side expression. - * - * @return The left-hand-side expression. - */ - const expression_node_p& lhs() const { return m_lhs; }; - - /** - * @brief Returns this node's left-hand-side expression. - * - * @return The left-hand-side expression. - */ - expression_node_p& lhs() { return m_lhs; }; - - /** - * @brief Moves this node's left-hand-side expression. - * - * @return The moved left-hand-side expression. - */ - expression_node_p&& move_lhs() { return std::move(m_lhs); }; - - /** - * @brief Returns this node's right-hand-side expression. - * - * @return The right-hand-side expression. - */ - const expression_node_p& rhs() const { return m_rhs; }; - - /** - * @brief Returns this node's right-hand-side expression. - * - * @return The right-hand-side expression. - */ - expression_node_p& rhs() { return m_rhs; }; - - /** - * @brief Moves this node's right-hand-side expression. - * - * @return The moved right-hand-side expression. - */ - expression_node_p&& move_rhs() { return std::move(m_rhs); }; -public: - expression_node_t expression_type() const override { return expression_node_t::Binop; } -public: - void accept(visitor& visitor) const override; - - std::ostream& print(std::ostream& os) const override; -protected: - bool equal(const node& rhs) const override; -private: - binop_expression_node_t m_type; - expression_node_p m_lhs; - expression_node_p m_rhs; -}; - -/** - * @brief Variable assignment expression AST node. - */ -class var_assign_expression_node final : public expression_node { -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(struct location location, expression_node_p&& lhs, expression_node_p&& 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(struct location location, - binop_expression_node_t compound, - expression_node_p&& lhs, - expression_node_p&& 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. - * - * @return The compound operation type. - */ - binop_expression_node_t compound() const { return m_compound; } - - /** - * @brief Returns this node's left-hand-side expression. - * - * @return The left-hand-side expression. - */ - const expression_node_p& lhs() const { return m_lhs; } - - /** - * @brief Returns this node's right-hand-side expression. - * - * @return The right-hand-side expression. - */ - const expression_node_p& rhs() const { return m_rhs; } -public: - /** - * @brief Returns this node's expression type. - * - * @return expression_node_t::VarAssign. - */ - expression_node_t expression_type() const override { return expression_node_t::VarAssign; } -public: - void accept(visitor& visitor) const override; - - std::ostream& print(std::ostream& os) const override; -protected: - bool equal(const node& rhs) const override; -private: - binop_expression_node_t m_compound; - expression_node_p m_lhs; - expression_node_p m_rhs; -}; - -/** - * @brief Function call expression AST node. - */ -class function_call_expression_node final : public expression_node { -public: - /** - * @brief Construct a new function call expression AST node. - * - * @param location Node location. - * @param func Left-hand-side expression. - * @param args Function arguments. - */ - function_call_expression_node(struct location location, - expression_node_p&& func, - std::vector&& args) - : expression_node(location), m_func(std::move(func)), m_args(std::move(args)) {} - - /** - * @brief Returns this node's left-hand-side expression. - * - * @return The left-hand-side expression. - */ - const expression_node_p& func() const { return m_func; } - - /** - * @brief Returns this node's argument expressions. - * - * @return The argument expressions. - */ - const std::vector& args() const { return m_args; } -public: - /** - * @brief Returns this node's expression type. - * - * @return expression_node_t::FuncCall. - */ - expression_node_t expression_type() const override { return expression_node_t::FuncCall; } -public: - void accept(visitor& visitor) const override; - - std::ostream& print(std::ostream& os) const override; -protected: - bool equal(const node& rhs) const override; -private: - expression_node_p m_func; - std::vector m_args; -}; - -} // namespace ast -} // namespace furc - -#endif // FURC_AST_EXPRESSION_HPP diff --git a/furc/include/furc/ast/fwd.hpp b/furc/include/furc/ast/fwd.hpp deleted file mode 100644 index 1879464..0000000 --- a/furc/include/furc/ast/fwd.hpp +++ /dev/null @@ -1,259 +0,0 @@ -#ifndef FURC_AST_FWD_HPP -#define FURC_AST_FWD_HPP - -#include "furc/diag.hpp" -#include "furlang/result.hpp" - -#include -#include -#include - -namespace furc { - -/** - * @brief Abstract Syntax Tree definitions. - */ -namespace ast { - -/** - * @brief AST error. - */ -struct error { - location location; /**< Location of the error. */ - - /** - * @brief Compares two AST errors for equality. - * - * @param other Error to compare against. - * @return true if the errors are equal. - */ - bool operator==(const error& other) const { return location == other.location; } - - /** - * @brief Compares two AST errors for inequality. - * - * @param other Error to compare against. - * @return true if the errors are not equal. - */ - bool operator!=(const error& other) const { return !this->operator==(other); } - - /** - * @brief Prints an AST error to output stream. - * - * @param os Output stream. - * @param error AST error to print. - * @return The output stream. - */ - friend std::ostream& operator<<(std::ostream& os, const error& error); -}; - -class node; - -/** - * @brief Alias for a shared pointer to node. - * - * @tparam T AST node type. - */ -template -using node_p = std::shared_ptr; - -/** - * @brief Alias for node result. - * - * @tparam T AST node type. - */ -template -using node_r = furlang::result, error>; - -class expression_node; - -using expression_node_p = node_p; /**< Alias for a shared pointer to expression_node. */ - -using expression_node_r = node_r; /**< Alias for expression_node result */ - -class type; - -using type_r = furlang::result; /**< Alias for AST type result */ - -class declaration_node; - -using declaration_node_p = node_p; /**< Alias for a shared pointer to declaration_node. */ - -using declaration_node_r = node_r; /**< Alias for declaration_node result */ - -class statement_node; - -using statement_node_p = node_p; /**< Alias for a shared pointer to statement_node. */ - -using statement_node_r = node_r; /**< Alias for statement_node result */ - -class program_node; - -using program_node_p = node_p; /**< Alias for a shared pointer to program_node. */ - -using program_node_r = node_r; /**< Alias for program_node result */ - -/** - * @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; - -using string_literal_node_p = node_p; /**< Alias for a shared pointer to string_literal_node */ - -using string_literal_node_r = node_r; /**< Alias for string_literal_node result */ - -/** - * @brief Integer literal AST node. - */ -using integer_literal_node = literal_node; - -using integer_literal_node_p = node_p; /**< Alias for a shared pointer to integer_literal_node */ - -using integer_literal_node_r = node_r; /**< Alias for integer_literal_node result */ - -class var_read_expression_node; - -using var_read_expression_node_p = - node_p; /**< Alias for a shared pointer to var_read_expression_node. */ - -using var_read_expression_node_r = node_r; /**< Alias for var_read_expression_node result */ - -class unary_op_expression_node; - -using unary_op_expression_node_p = - node_p; /**< Alias for a shared pointer to unaryop_expression_node. */ - -using unary_op_expression_node_r = node_r; /**< Alias for unaryop_expression_node result */ - -class binary_op_expression_node; - -using binary_op_expression_node_p = - node_p; /**< Alias for a shared pointer to binop_expression_node. */ - -using binary_op_expression_node_r = node_r; /**< Alias for binop_expression_node result */ - -class var_assign_expression_node; - -using var_assign_expression_node_p = - node_p; /**< Alias for a shared pointer to var_assign_expression_node. */ - -using var_assign_expression_node_r = - node_r; /**< Alias for var_assign_expression_node result */ - -class function_call_expression_node; - -using function_call_expression_node_p = - node_p; /**< Alias for a shared pointer to function_call_expression_node. */ - -using function_call_expression_node_r = - node_r; /**< Alias for function_call_expression_node result. */ - -/** - * @brief List of statements. - */ -struct body { - /** - * @brief Location of the opening curly. - */ - location begin; - - /** - * @brief Location of the closing curly. - */ - location end; - - /** - * @brief List of statements. - */ - std::vector statements; - - /** - * @brief Compares two bodies for equality. - * - * @param rhs Body to compare against. - * @return true if the bodies are equal. - */ - bool operator==(const body& rhs) const { - return begin == rhs.begin && end == rhs.end && statements == rhs.statements; - } - - /** - * @brief Compares two bodies for inequality. - * - * @param rhs Body to compare against. - * @return true if the bodies are not equal. - */ - bool operator!=(const body& rhs) const { return !this->operator==(rhs); } - - /** - * @brief Prints a body to an output stream. - * - * @param os Output stream. - * @param body Body to print. - * @return The output stream. - */ - friend std::ostream& operator<<(std::ostream& os, const body& body); -}; - -/** - * @brief Alias for body result. - * @see body - */ -using body_r = furlang::result; - -class function_declaration_node; - -using function_declaration_node_p = - node_p; /**< Alias for a shared pointer to function_declaration_node. */ - -using function_declaration_node_r = - node_r; /**< Alias for function_declaration_node result */ - -class function_definition_node; - -using function_definition_node_p = - node_p; /**< Alias for a shared pointer to function_definition_node. */ - -using function_definition_node_r = node_r; /**< Alias for function_definition_node result */ - -class return_statement_node; - -using return_statement_node_p = - node_p; /**< Alias for a shared pointer to return_statement_node. */ - -using return_statement_node_r = node_r; /**< Alias for return_statement_node result */ - -class if_statement_node; - -using if_statement_node_p = node_p; /**< Alias for a shared pointer to if_statement_node. */ - -using if_statement_node_r = node_r; /**< Alias for if_statement_node result */ - -class compound_statement_node; - -using compound_statement_node_p = - node_p; /**< Alias for a shared pointer to compound_statement_node. */ - -using compound_statement_node_r = node_r; /**< Alias for compound_statement_node result */ - -class while_statement_node; - -using while_statement_node_p = node_p; /**< Alias for a shared pointer to while_statement_node. */ - -using while_statement_node_r = node_r; /**< Alias for while_statement_node result */ - -} // namespace ast -} // namespace furc - -#endif // FURC_AST_FWD_HPP diff --git a/furc/include/furc/ast/literal.hpp b/furc/include/furc/ast/literal.hpp deleted file mode 100644 index 2a08c88..0000000 --- a/furc/include/furc/ast/literal.hpp +++ /dev/null @@ -1,102 +0,0 @@ -// 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" - -namespace furc { -namespace ast { - -/** - * @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. - * - * @return node_t::Literal. - */ - node_t category() const override { return node_t::Literal; } - - /** - * @brief Returns this node's expression type. - * - * @return expression_node_t::Literal. - */ - expression_node_t expression_type() const override { return expression_node_t::Literal; } - - /** - * @brief Returns this node's literal type. - * - * @return The literal type. - */ - 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 p_value; } -public: - void accept(visitor& visitor) const override { visitor.visit(*this); } - - std::ostream& print(std::ostream& os) const override { return os << p_value; } -protected: - 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: - value_type p_value; /**< Node value. */ -}; - -} // namespace ast -} // namespace furc - -#endif // FURC_AST_LITERAL_HPP - -// NOLINTEND(portability-template-virtual-member-function) \ No newline at end of file diff --git a/furc/include/furc/ast/node.hpp b/furc/include/furc/ast/node.hpp deleted file mode 100644 index 8d9807c..0000000 --- a/furc/include/furc/ast/node.hpp +++ /dev/null @@ -1,166 +0,0 @@ -#ifndef FURC_AST_NODE_HPP -#define FURC_AST_NODE_HPP - -#include "furc/ast/fwd.hpp" -#include "furc/ast/visitor.hpp" - -namespace furc { -namespace ast { - -/** - * @brief Node category. - */ -enum class node_t { - Literal, /**< Literal. */ - Expression, /**< Expression. */ - Statement, /**< Statement. */ - Declaration, /**< Declaration. */ - Program, /**< Program. */ -}; - -/** - * @brief Prints a node type (category) to an output stream. - * - * @param os Output stream. - * @param type Type to print. - * @return The output stream. - */ -static inline std::ostream& operator<<(std::ostream& os, node_t type) { - switch (type) { - case node_t::Literal: return os << "literal"; - case node_t::Expression: return os << "expression"; - case node_t::Statement: return os << "statement"; - case node_t::Declaration: return os << "declaration"; - case node_t::Program: return os << "program"; - } - return os; -} - -/** - * @brief AST node interface. - */ -class node { -public: - node() = default; - virtual ~node() = default; - - /** - * @brief Move constructor. - * - * Constructs a node by transferring the state of another node. - * - * @param other Node to move from. - */ - node(node&& other) = default; - node(const node&) = delete; - - /** - * @brief Move constructor. - * - * Constructs a node by transferring the state of another node. - * - * @param other Node to move from. - */ - node& operator=(node&& other) = default; - node& operator=(const node&) = delete; -public: - /** - * @brief Returns the category of this AST node. - * @see node_t - * - * @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. - * - * Nodes are equal if they have the same category and - * their derived-class-specific contents are equal. - * - * @param rhs Node to compare against. - * @return true if the nodes are equal. - */ - bool operator==(const node& rhs) const { return category() == rhs.category() && equal(rhs); } - - /** - * @brief Compares two nodes for inequality. - * - * @param rhs Node to compare against. - * @return true if the nodes are not equal. - */ - bool operator!=(const node& rhs) const { return !this->operator==(rhs); } -public: - /** - * @brief Accepts a visitor. - * - * Dispatches to the visitor overload corresponding to the concrete node type. - * - * @param visitor Visitor instance. - */ - virtual void accept(visitor& visitor) const = 0; - - /** - * @brief Prints a node to an output stream. - * - * @param os Output stream. - * @return The output stream. - */ - virtual std::ostream& print(std::ostream& os) const = 0; - - /** - * @brief Prints a node to an output stream. - * - * Equivalent to calling node.print(os). - * - * @param os Output stream. - * @param node Node to print. - * @return The output stream. - */ - friend std::ostream& operator<<(std::ostream& os, const node& node) { - return node.print(os << node.location() << ": "); - } -protected: - /** - * @brief Compares two nodes for equality. - * - * @param rhs Node to compare against. - * @return true if nodes are equal. - */ - 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 - -#endif // FURC_AST_NODE_HPP \ No newline at end of file diff --git a/furc/include/furc/ast/program.hpp b/furc/include/furc/ast/program.hpp deleted file mode 100644 index b050e62..0000000 --- a/furc/include/furc/ast/program.hpp +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef FURC_AST_PROGRAM_HPP -#define FURC_AST_PROGRAM_HPP - -#include "furc/ast/node.hpp" - -#include - -namespace furc { -namespace ast { - -/** - * @brief Program AST node. - */ -class program_node final : public abstract_node { -public: - /** - * @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: - /** - * @brief Adds a declaration to this program. - * - * @param declaration Declaration to add. - */ - void push(declaration_node_p&& declaration) { m_declarations.push_back(std::move(declaration)); } - - /** - * @brief Returns a list of declarations of this program. - * - * @return The list of this program's declarations. - */ - const std::vector& declarations() const { return m_declarations; } -public: - void accept(visitor& visitor) const override; - - std::ostream& print(std::ostream& os) const override; -protected: - bool equal(const node& rhs) const override; -private: - std::vector m_declarations; -}; - -} // namespace ast -} // namespace furc - -#endif // FURC_AST_PROGRAM_HPP \ No newline at end of file diff --git a/furc/include/furc/ast/statement.hpp b/furc/include/furc/ast/statement.hpp deleted file mode 100644 index 91226d1..0000000 --- a/furc/include/furc/ast/statement.hpp +++ /dev/null @@ -1,244 +0,0 @@ -#ifndef FURC_AST_STATEMENT_HPP -#define FURC_AST_STATEMENT_HPP - -#include "furc/ast/fwd.hpp" -#include "furc/ast/node.hpp" - -#include - -namespace furc { -namespace ast { - -/** - * @brief Statement node type. - */ -enum class statement_node_t { - Expression, /**< Expression */ - Declaration, /**< Declaration */ - Return, /**< Return statement */ - If, /**< If statement */ - Compound, /**< Compound statement */ - While, /**< While loop statement. */ -}; - -/** - * @brief Statement AST node. - */ -class statement_node : public virtual node { -public: - /** - * @brief Returns this node's category. - * - * @return node_t::Statement. - */ - node_t category() const override { return node_t::Statement; } - - /** - * @brief Returns this node's statement type. - * - * @return The statement type. - */ - virtual statement_node_t statement_type() const = 0; -protected: - bool equal(const node& rhs) const override; -}; - -/** - * @brief Return statement AST node. - */ -class return_statement_node final : public statement_node, public abstract_node { -public: - using value_type = std::optional; /**< Value type. */ -public: - /** - * @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(struct location location, expression_node_p&& value) - : abstract_node(location), m_value(std::move(value)) {} -public: - /** - * @brief Returns this node's return value handle. - * - * @return The return value handle. - */ - value_type value() const { return m_value; } -public: - /** - * @brief Returns this node's statement type. - * - * @return statement_node_t::Return. - */ - statement_node_t statement_type() const override { return statement_node_t::Return; } -public: - void accept(visitor& visitor) const override; - - std::ostream& print(std::ostream& os) const override; -protected: - bool equal(const node& rhs) const override; -private: - value_type m_value; /**< Return value handle. */ -}; - -/** - * @brief If statement AST 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(struct location location, expression_node_p&& cond, statement_node_p&& 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(struct location location, - expression_node_p&& cond, - statement_node_p&& then, - statement_node_p&& 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. - * - * @return The condition expression handle. - */ - expression_node_p cond() const { return m_cond; } - - /** - * @brief Returns this node's then statement handle. - * - * @return The then statement handle. - */ - const statement_node_p& then() const { return m_then; } - - /** - * @brief Returns this node's else statement handle. - * - * @return The else statement handle. - */ - const std::optional& elze() const { return m_else; } -public: - /** - * @brief Returns this node's statement type. - * - * @return statement_node_t::If. - */ - statement_node_t statement_type() const override { return statement_node_t::If; } -public: - void accept(visitor& visitor) const override; - - std::ostream& print(std::ostream& os) const override; -protected: - bool equal(const node& rhs) const override; -private: - expression_node_p m_cond; /**< The condition expression handle */ - statement_node_p m_then; /**< The then statement handle */ - std::optional m_else; /**< The else statement handle */ -}; - -/** - * @brief Compound statement AST 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(struct location location, body&& body) - : abstract_node(location), m_body(std::move(body)) {} -public: - /** - * @brief Returns this node's body handle. - * - * @return The body handle. - */ - const body& body() const { return m_body; } -public: - /** - * @brief Returns this node's statement type. - * - * @return statement_node_t::Compound. - */ - statement_node_t statement_type() const override { return statement_node_t::Compound; } -public: - void accept(visitor& visitor) const override; - - std::ostream& print(std::ostream& os) const override; -protected: - bool equal(const node& rhs) const override; -private: - struct body m_body; /**< The body handle. */ -}; - -/** - * @brief while statement AST node. - */ -class while_statement_node final : public statement_node, public abstract_node { -public: - /** - * @brief Construct a new while statement AST node. - * - * @param location Node location. - * @param body Body handle. - */ - while_statement_node(struct location location, expression_node_p&& cond, statement_node_p&& body) - : abstract_node(location), m_cond(std::move(cond)), m_body(std::move(body)) {} -public: - /** - * @brief Returns this node's condition expression. - * - * @return The condition expression. - */ - const expression_node_p& condition() const { return m_cond; } - - /** - * @brief Returns this node's body handle. - * - * @return The body handle. - */ - const statement_node_p& body() const { return m_body; } -public: - /** - * @brief Returns this node's statement type. - * - * @return statement_node_t::while. - */ - statement_node_t statement_type() const override { return statement_node_t::While; } -public: - void accept(visitor& visitor) const override; - - std::ostream& print(std::ostream& os) const override; -protected: - bool equal(const node& rhs) const override; -private: - expression_node_p m_cond; /**< The condition expression. */ - statement_node_p m_body; /**< The body handle. */ -}; - -} // namespace ast -} // namespace furc - -#endif // FURC_AST_STATEMENT_HPP diff --git a/furc/include/furc/ast/visitor.hpp b/furc/include/furc/ast/visitor.hpp deleted file mode 100644 index dece12f..0000000 --- a/furc/include/furc/ast/visitor.hpp +++ /dev/null @@ -1,152 +0,0 @@ -#ifndef FURC_AST_VISITOR_HPP -#define FURC_AST_VISITOR_HPP - -#include "furc/ast/fwd.hpp" - -namespace furc { -namespace ast { - -/** - * @brief Visitor pattern class for AST nodes. - */ -class visitor { -public: - visitor() = default; - virtual ~visitor() = default; - - /** - * @brief Move constructor. - */ - visitor(visitor&&) = default; - - /** - * @brief Move constructor. - */ - visitor& operator=(visitor&&) = default; - - /** - * @brief Copy constructor. - */ - visitor(const visitor&) = default; - - /** - * @brief Copy constructor. - */ - visitor& operator=(const visitor&) = default; -public: - /** - * @brief Visit a string_literal_node. - * @see string_literal_node - * - * @param node Node. - */ - virtual void visit(const string_literal_node& node) {} - - /** - * @brief Visit a integer_literal_node. - * @see integer_literal_node - * - * @param node Node. - */ - virtual void visit(const integer_literal_node& node) {} - - /** - * @brief Visit a var_read_expression_node. - * @see var_read_expression_node - * - * @param node Node. - */ - virtual void visit(const var_read_expression_node& node) {} - - /** - * @brief Visit a unaryop_expression_node. - * @see unaryop_expression_node - * - * @param node Node. - */ - virtual void visit(const unary_op_expression_node& node) {} - - /** - * @brief Visit a binop_expression_node. - * @see binop_expression_node - * - * @param node Node. - */ - virtual void visit(const binary_op_expression_node& node) {} - - /** - * @brief Visit a var_assign_expression_node. - * @see var_assign_expression_node - * - * @param node Node. - */ - virtual void visit(const var_assign_expression_node& node) {} - - /** - * @brief Visit a function_call_expression_node. - * @see function_call_expression_node - * - * @param node Node. - */ - virtual void visit(const function_call_expression_node& node) {} - - /** - * @brief Visit a function_declaration_node. - * @see function_declaration_node - * - * @param node Node. - */ - virtual void visit(const function_declaration_node& node) {} - - /** - * @brief Visit a function_definition_node. - * @see function_definition_node - * - * @param node Node. - */ - virtual void visit(const function_definition_node& node) {} - - /** - * @brief Visit a return_statement_node. - * @see return_statement_node - * - * @param node Node. - */ - virtual void visit(const return_statement_node& node) {} - - /** - * @brief Visit a if_statement_node. - * @see if_statement_node - * - * @param node Node. - */ - virtual void visit(const if_statement_node& node) {} - - /** - * @brief Visit a compound_statement_node. - * @see compound_statement_node - * - * @param node Node. - */ - virtual void visit(const compound_statement_node& node) {} - - /** - * @brief Visit a while_statement_node. - * @see while_statement_node - * - * @param node Node. - */ - virtual void visit(const while_statement_node& node) {} - - /** - * @brief Visit an AST error. - * - * @param error AST error. - */ - virtual void visit_error(const ast::error& error) {} -}; - -} // namespace ast -} // namespace furc - -#endif // FURC_AST_VISITOR_HPP diff --git a/furc/include/furc/back/furvm.hpp b/furc/include/furc/back/furvm.hpp deleted file mode 100644 index 5da948f..0000000 --- a/furc/include/furc/back/furvm.hpp +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef FURC_BACK_FURVM_HPP -#define FURC_BACK_FURVM_HPP - -#include "furlang/ir/operand.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace furc { -namespace back { - -class furvm_generator { -public: - furvm_generator() = default; -public: - static furvm::mod generate(furlang::ir::mod& mod); -private: - static void generate_function(furvm::mod& mod, const furlang::ir::function& function); - - struct function_context { - std::unordered_map blockOffsets; - std::unordered_map> incompleteJumps; - - std::unordered_map variables; - furvm::variable_t variableCounter{ 0 }; - }; - - static void generate_instruction(furvm::mod& mod, function_context& ctx, const furlang::ir::instruction& instr); - static void generate_operand(furvm::mod& mod, function_context& ctx, const furlang::ir::operand& operand); - - static void generate_jump(furvm::mod& mod, function_context& ctx, furlang::ir::block_index block, bool conditional); -}; - -} // namespace back -} // namespace furc - -#endif // FURC_BACK_FURVM_HPP diff --git a/furc/include/furc/diag.hpp b/furc/include/furc/diag.hpp deleted file mode 100644 index efe204b..0000000 --- a/furc/include/furc/diag.hpp +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef FURC_DIAG_HPP -#define FURC_DIAG_HPP - -#include -#include - -namespace furc { - -/** - * @brief A location in file. - */ -struct location { - std::string_view filename; /**< File's name */ - std::size_t line = 0; /**< Line */ - std::size_t column = 0; /**< Column */ - - /** - * @brief Compare two locations for equality. - * - * @param rhs Location to compare against. - * @return true if the locations are equal. - */ - bool operator==(const location& rhs) const { - return filename == rhs.filename && line == rhs.line && column == rhs.column; - } - - /** - * @brief Compare two locations for inequality. - * - * @param rhs Location to compare against. - * @return true if the locations are not equal. - */ - bool operator!=(const location& rhs) const { return !this->operator==(rhs); } -}; - -static inline std::ostream& operator<<(std::ostream& os, const location& location) { - return os << location.filename << ':' << location.line + 1 << ':' << location.column + 1; -} - -} // namespace furc - -#endif // FURC_DIAG_HPP \ No newline at end of file diff --git a/furc/include/furc/front/ir_generator.hpp b/furc/include/furc/front/ir_generator.hpp deleted file mode 100644 index e882505..0000000 --- a/furc/include/furc/front/ir_generator.hpp +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef FURC_FRONT_IR_GENERATOR_HPP -#define FURC_FRONT_IR_GENERATOR_HPP - -#include "furc/ast/fwd.hpp" -#include "furc/ast/visitor.hpp" -#include "furlang/ir/module.hpp" - -#include - -namespace furc { -namespace front { - -using ir_register = std::uint32_t; - -class ir_generator final : public ast::visitor { -public: - ir_generator() = default; - ~ir_generator() override = default; - - ir_generator(ir_generator&&) = default; - ir_generator& operator=(ir_generator&&) = default; - ir_generator(const ir_generator&) = delete; - ir_generator& operator=(const ir_generator&) = delete; -public: - furlang::ir::mod&& move_module() { return std::move(m_module); } -public: - void visit(const ast::function_definition_node& funcDef) override; - void visit(const ast::function_declaration_node& funcDecl) override; - void visit(const ast::return_statement_node& returnStmt) override; - void visit(const ast::if_statement_node& node) override; - void visit(const ast::while_statement_node& node) override; - void visit(const ast::compound_statement_node& node) override; - void visit(const ast::string_literal_node& node) override; - void visit(const ast::integer_literal_node& node) override; - void visit(const ast::var_read_expression_node& node) override; - void visit(const ast::unary_op_expression_node& node) override; - void visit(const ast::binary_op_expression_node& node) override; - void visit(const ast::var_assign_expression_node& node) override; - void visit(const ast::function_call_expression_node& node) override; -private: - template - void push(Args&&... args) { - if (!m_currentBlock->emplace(std::forward(args)...)) { - throw std::runtime_error("block exited too soon"); - } - } - - furlang::ir::block_index push_block(bool validate = true); -private: - furlang::ir::mod m_module; - std::unique_ptr m_currentFunction; - std::shared_ptr m_currentBlock; - ir_register m_registerCounter = 0; - - std::unordered_map m_variables; -}; - -} // namespace front -} // namespace furc - -#endif // FURC_FRONT_IR_GENERATOR_HPP diff --git a/furc/include/furc/front/lexer.hpp b/furc/include/furc/front/lexer.hpp deleted file mode 100644 index b05bb73..0000000 --- a/furc/include/furc/front/lexer.hpp +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef FURC_FRONT_LEXER_HPP -#define FURC_FRONT_LEXER_HPP - -#include "furc/front/token.hpp" - -namespace furc { -namespace front { - -/** - * @brief Lexer. - * - * Furlang's lazy tokenizer. - */ -class lexer { -public: - lexer() = default; - - /** - * @brief Construct a new lexer. - * - * @param filename Filename for debugging. - * @param content Content. - */ - lexer(std::string_view filename, std::string_view content); - ~lexer() = default; - - /** - * @brief Move constructor. - */ - lexer(lexer&&) = default; - - lexer(const lexer&) = delete; - - /** - * @brief Move constructor. - */ - lexer& operator=(lexer&&) = default; - - lexer& operator=(const lexer&) = delete; -public: - /** - * @brief Returns a handle to next token. - * - * @return The token handle. - */ - token_r next_token(); - - /** - * @brief Checks whether the cursor is at the EOF. - * - * @return true if the cursor is at the EOF. - */ - bool empty() const { return m_cursor >= m_content.size(); } -private: - void next(); - char get(std::size_t offset = 0) const; - void skip_spaces(); - location current_location(); -private: - std::string_view m_filename; - std::string_view m_content; - std::size_t m_cursor = 0; - std::size_t m_row = 0; - std::size_t m_lineStart = 0; -}; - -} // namespace front -} // namespace furc - -#endif // FURC_FRONT_LEXER_HPP \ No newline at end of file diff --git a/furc/include/furc/front/parser.hpp b/furc/include/furc/front/parser.hpp deleted file mode 100644 index 3e760fe..0000000 --- a/furc/include/furc/front/parser.hpp +++ /dev/null @@ -1,86 +0,0 @@ -#ifndef FURC_FRONT_PARSER_HPP -#define FURC_FRONT_PARSER_HPP - -#include "furc/ast/declaration.hpp" -#include "furc/ast/fwd.hpp" -#include "furc/front/lexer.hpp" -#include "furlang/arena.hpp" - -#include - -namespace furc { -namespace front { - -/** - * @brief Parser. - * - * Furlang's parser. - */ -class parser final { -public: - /** - * @brief Construct a new parser from content. - * - * @param filename Filename for debugging. - * @param content Content. - */ - parser(furlang::arena& arena, std::string_view filename, std::string_view content); - - /** - * @brief Construct a new parser from file. - * - * Constructs a lexer with content read from file passed through \p filename. - * - * @param filename Name of the file. - */ - parser(furlang::arena& arena, std::string_view filename); - - ~parser() = default; - - /** - * @brief Move constructor. - */ - parser(parser&&) = default; - - /** - * @brief Move constructor. - */ - parser& operator=(parser&&) = default; - - parser(const parser&) = delete; - parser& operator=(const parser&) = delete; -public: - /** - * @brief Returns a parsed program. - * - * @return Handle to an AST node of the program. - */ - ast::program_node_r parse() &; -private: - ast::type_r parse_type(); - - ast::declaration_node_r parse_declaration(); - ast::statement_node_r parse_statement(); - ast::expression_node_r parse_expression(std::uint32_t precedence = 16); - - ast::expression_node_r parse_expression_primary(); - ast::expression_node_r parse_expression_unary(std::uint32_t precedence); - ast::expression_node_r parse_expression_rhs(ast::expression_node_p&& init, std::uint32_t precedence); - - ast::body_r parse_body(); -private: - token_r next_token(); - const token_r& peek_token(); - token_r eat_token(token_t type); -private: - std::string m_filename; - std::string m_content; - lexer m_lexer; - furlang::arena* m_arena; - std::vector m_peekBuffer; -}; - -} // namespace front -} // namespace furc - -#endif // FURC_FRONT_PARSER_HPP diff --git a/furc/include/furc/front/post_process.hpp b/furc/include/furc/front/post_process.hpp deleted file mode 100644 index 1145fb4..0000000 --- a/furc/include/furc/front/post_process.hpp +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef FURC_FRONT_POST_PROCESS_HPP -#define FURC_FRONT_POST_PROCESS_HPP - -#include "furlang/ir/module.hpp" - -#include - -namespace furc { -namespace front { - -/** - * @brief Post process pipeline. - */ -class post_process { -public: - enum stage { // NOLINT - Ssa, - Sccp, - Adce, - DeSsa, - }; -public: - post_process() = default; - ~post_process() = default; - - post_process(post_process&&) noexcept = default; - post_process& operator=(post_process&&) noexcept = default; - post_process(const post_process&) = delete; - post_process& operator=(const post_process&) = delete; -public: - void push_stage(stage stage) { m_stages.push_back(stage); } -public: - void process(furlang::ir::mod& mod); -private: - std::vector m_stages; -}; - -} // namespace front -} // namespace furc - -#endif // FURC_FRONT_POST_PROCESS_HPP diff --git a/furc/include/furc/front/token.hpp b/furc/include/furc/front/token.hpp deleted file mode 100644 index d648368..0000000 --- a/furc/include/furc/front/token.hpp +++ /dev/null @@ -1,412 +0,0 @@ -#ifndef FURC_FRONT_TOKEN_HPP -#define FURC_FRONT_TOKEN_HPP - -#include "furc/diag.hpp" -#include "furlang/result.hpp" - -#include -#include -#include -#include - -namespace furc { -namespace front { - -/** - * @brief Token type. - */ -enum class token_t { - None, /**< None */ - Identifier, /**< Identifier */ - String, /**< String */ - Keyword, /**< Keyword */ - Integer, /**< Integer */ - - LParen, /**< `(` */ - RParen, /**< `)` */ - LBrace, /**< `{` */ - RBrace, /**< `}` */ - LBracket, /**< `[` */ - RBracket, /**< `]` */ - Semicolon, /**< `;` */ - Colon, /**< `:` */ - Comma, /**< `,` */ - Dot, /**< `.` */ - - Plus, /**< `+` */ - Minus, /**< `-` */ - Star, /**< `*` */ - Slash, /**< `/` */ - Percent, /**< `%` */ - DPlus, /**< `++` */ - DMinus, /**< `--` */ - - Eq, /**< `=` */ - PlusEq, /**< `+=` */ - MinusEq, /**< `-=` */ - StarEq, /**< `*=` */ - SlashEq, /**< `/=` */ - PercentEq, /**< `%=` */ - - DEq, /**< `==` */ - NotEq, /**< `!=` */ - LessThan, /**< `<` */ - GreaterThan, /**< `>` */ - LessEq, /**< `<=` */ - GreaterEq, /**< `>=` */ - - SlimArrow, /**< `->` */ - FatArrow, /**< `=>` */ -}; - -static inline std::ostream& operator<<(std::ostream& os, token_t type) { - switch (type) { - case token_t::None: return os << "none"; - case token_t::Identifier: return os << "identifier"; - case token_t::String: return os << "string"; - case token_t::Keyword: return os << "keyword"; - case token_t::Integer: return os << "integer"; - case token_t::LParen: return os << "'('"; - case token_t::RParen: return os << "')'"; - case token_t::LBrace: return os << "'{'"; - case token_t::RBrace: return os << "'}'"; - case token_t::LBracket: return os << "'['"; - case token_t::RBracket: return os << "']'"; - case token_t::Semicolon: return os << "';'"; - case token_t::Colon: return os << "':'"; - case token_t::Comma: return os << "','"; - case token_t::Dot: return os << "'.'"; - case token_t::Plus: return os << "'+'"; - case token_t::Minus: return os << "'-'"; - case token_t::Star: return os << "'*'"; - case token_t::Slash: return os << "'/'"; - case token_t::Percent: return os << "'%'"; - case token_t::DPlus: return os << "++"; - case token_t::DMinus: return os << "--"; - case token_t::Eq: return os << "="; - case token_t::PlusEq: return os << "+="; - case token_t::MinusEq: return os << "-="; - case token_t::StarEq: return os << "*="; - case token_t::SlashEq: return os << "/="; - case token_t::PercentEq: return os << "%="; - case token_t::DEq: return os << "=="; - case token_t::NotEq: return os << "!="; - case token_t::LessThan: return os << "<"; - 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; -} - -static inline std::string operator+(const std::string& str, token_t type) { - switch (type) { - case token_t::None: return str + "none"; - case token_t::Identifier: return str + "identifier"; - case token_t::String: return str + "string"; - case token_t::Keyword: return str + "keyword"; - case token_t::Integer: return str + "integer"; - case token_t::LParen: return str + "'('"; - case token_t::RParen: return str + "')'"; - case token_t::LBrace: return str + "'{'"; - case token_t::RBrace: return str + "'}'"; - case token_t::LBracket: return str + "'['"; - case token_t::RBracket: return str + "']'"; - case token_t::Semicolon: return str + "';'"; - case token_t::Colon: return str + "':'"; - case token_t::Comma: return str + "','"; - case token_t::Dot: return str + "'.'"; - case token_t::Plus: return str + "'+'"; - case token_t::Minus: return str + "'-'"; - case token_t::Star: return str + "'*'"; - case token_t::Slash: return str + "'/'"; - case token_t::Percent: return str + "'%'"; - case token_t::DPlus: return str + "++"; - case token_t::DMinus: return str + "--"; - case token_t::Eq: return str + "="; - case token_t::PlusEq: return str + "+="; - case token_t::MinusEq: return str + "-="; - case token_t::StarEq: return str + "*="; - case token_t::SlashEq: return str + "/="; - case token_t::PercentEq: return str + "%="; - case token_t::DEq: return str + "=="; - case token_t::NotEq: return str + "!="; - case token_t::LessThan: return str + "<"; - 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; -} - -/** - * @brief Keyword token. - */ -enum class keyword_token { - None, /**< None */ - Func, /**< `func` */ - Return, /**< `return` */ - If, /**< `if` */ - Else, /**< `else` */ - While, /**< `while` */ - Import, /**< `import` */ - Native, /**< `native` */ - Public, /**< `public` */ - Private, /**< `private` */ - Pointerof, /**< `pointerof` */ - Sizeof, /**< `sizeof` */ - - Int32, /**< `int32` */ -}; - -static inline std::ostream& operator<<(std::ostream& os, keyword_token keyword) { - switch (keyword) { - case keyword_token::None: return os << "none"; - case keyword_token::Func: return os << "func"; - case keyword_token::Return: return os << "return"; - 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::Public: return os << "public"; - case keyword_token::Private: return os << "private"; - case keyword_token::Pointerof: return os << "pointerof"; - case keyword_token::Sizeof: return os << "sizeof"; - case keyword_token::Int32: return os << "int32"; - } - return os; -} - -static inline std::string operator+(const std::string& str, keyword_token keyword) { - switch (keyword) { - case keyword_token::None: return str + "none"; - case keyword_token::Func: return str + "func"; - case keyword_token::Return: return str + "return"; - 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::Public: return str + "public"; - case keyword_token::Private: return str + "private"; - case keyword_token::Pointerof: return str + "pointerof"; - case keyword_token::Sizeof: return str + "sizeof"; - case keyword_token::Int32: return str + "int32"; - } - return str; -} - -using integer_token = std::uint64_t; /**< Integer token. */ - -/** - * @brief Token. - */ -struct token { - location location; /**< Token location. */ - token_t type = token_t::None; /**< Token type. */ - - /** - * @brief Token's value. - */ - union value { - /** - * @brief Null value. For token_t::None, token_t::Plus, token_t::Minus, etc. - * @see token_t::None - */ - std::nullptr_t null; - - /** - * @brief String value. For token_t::Identifier and token_t::String. - * @see token_t::Identifier - * @see token_t::String - */ - std::string_view string; - - /** - * @brief Keyword value. For token_t::Keyword. - * @see token_t::Keyword. - */ - keyword_token keyword; - - /** - * @brief Integer value. For token_t::Integer. - * @see token_t::Integer - */ - integer_token integer; - - /** - * @brief Construct a new null value. - * - * @param value Null value. - */ - value(std::nullptr_t value = nullptr) - : null(value) {} - - /** - * @brief Construct a new string value. - * - * @param value The string. - */ - value(std::string_view value) - : string(value) {} - - /** - * @brief Construct a new keyword value. - * - * @param value The keyword. - */ - value(keyword_token value) - : keyword(value) {} - - /** - * @brief Construct a new integer value. - * - * @param value The integer. - */ - value(integer_token value) - : integer(value) {} - } value; /**< Token value. */ - - token() = default; - - /** - * @brief Construct a new null token. - * - * @param location Token's location. - * @param type Token's type. - */ - token(struct location location, token_t type) - : location(location), type(type) {} - - /** - * @brief Construct a new string token. - * - * @param location Token's location. - * @param type Token's type. - * @param value String value. - */ - token(struct location location, token_t type, std::string_view value) - : location(location), type(type), value(value) {} - - /** - * @brief Construct a new keyword token. - * - * @param location Token's location. - * @param keyword Keyword value. - */ - token(struct location location, keyword_token keyword) - : location(location), type(token_t::Keyword), value(keyword) {} - - /** - * @brief Construct a new integer token. - * - * @param location Token's location. - * @param integer Integer value. - */ - token(struct location location, integer_token integer) - : location(location), type(token_t::Integer), value(integer) {} - - /** - * @brief Returns pointer to this token's value. - * - * @return Pointer to the token's value. - */ - union value* operator->() { return &value; } - - /** - * @brief Returns constant pointer to this token's value. - * - * @return Pointer to the token's value. - */ - const union value* operator->() const { return &value; } - - /** - * @brief Compares two tokens for equality. - * - * @param rhs Token to compare against. - * @return true if the tokens are equal. - */ - bool operator==(const token& rhs) const { - if (type != rhs.type) return false; - switch (type) { - case token_t::Identifier: - case token_t::String: return value.string == rhs.value.string; - case token_t::Keyword: return value.keyword == rhs.value.keyword; - case token_t::Integer: return value.integer == rhs.value.integer; - default: return true; - } - } -}; - -static inline std::ostream& operator<<(std::ostream& os, const token& token) { - switch (token.type) { - case token_t::Identifier: - case token_t::String: return os << token.value.string; - case token_t::Keyword: return os << token.value.keyword; - case token_t::Integer: return os << token.value.integer; - default: return os << token.type; - } -} - -/** - * @brief Token error type - */ -enum class token_error_t { - EndOfFile, /**< End of file */ - UnexpectedEof, /**< Unexpected end of file */ - UnexpectedCharacter, /**< Unexpected character */ - UnexpectedToken, /**< Unexpected character */ - IntegerOverflow, /**< Integer overflow */ -}; - -/** - * @brief Token error - * - * For token_r alias. - */ -struct token_error { - location location; /**< Error location. */ - token_error_t type; /**< Error type. */ - std::string message; /**< Error message. */ - - /** - * @brief Compares two token errors for equality. - * - * @param rhs Error to compare against. - * @return true if the errors are equal. - */ - bool operator==(const token_error& rhs) const { - return location == rhs.location && type == rhs.type && message == rhs.message; - } - - /** - * @brief Compares two token errors for inequality. - * - * @param rhs Error to compare against. - * @return true if the errors are not equal. - */ - bool operator!=(const token_error& rhs) const { return !this->operator==(rhs); } - - /** - * @brief Prints a token error to an output stream. - * - * @param os Output stream. - * @param error Token error to print. - * @return The output stream. - */ - friend std::ostream& operator<<(std::ostream& os, const token_error& error) { - return os << error.location << ": error: unknown"; - } -}; - -using token_r = furlang::result; /**< Alias to a token result. */ - -} // namespace front -} // namespace furc - -#endif // FURC_FRONT_TOKEN_HPP diff --git a/furc/src/ast.cpp b/furc/src/ast.cpp deleted file mode 100644 index 95bc727..0000000 --- a/furc/src/ast.cpp +++ /dev/null @@ -1,251 +0,0 @@ -#include "furc/ast/declaration.hpp" -#include "furc/ast/expression.hpp" -#include "furc/ast/node.hpp" -#include "furc/ast/program.hpp" -#include "furc/ast/statement.hpp" - -#include - -namespace furc::ast { - -std::ostream& operator<<(std::ostream& os, const error& error) { - return os << error.location << ": ERROR: unknown"; -} - -bool expression_node::equal(const node& rhs) const { - return expression_type() == dynamic_cast(rhs).expression_type(); -} - -void var_read_expression_node::accept(visitor& visitor) const { - visitor.visit(*this); -} - -std::ostream& var_read_expression_node::print(std::ostream& os) const { - return os << m_name; -} - -bool var_read_expression_node::equal(const node& rhsNode) const { - const auto& rhs = dynamic_cast(rhsNode); - return expression_node::equal(rhsNode) && m_name == rhs.m_name; -} - -std::ostream& operator<<(std::ostream& os, unaryop_expression_node_t type) { - switch (type) { - case unaryop_expression_node_t::Positive: return os << "+"; - case unaryop_expression_node_t::Negative: return os << "-"; - case unaryop_expression_node_t::PrefixIncrement: - case unaryop_expression_node_t::PostfixIncrement: return os << "++"; - case unaryop_expression_node_t::PrefixDecrement: - case unaryop_expression_node_t::PostfixDecrement: return os << "--"; - case unaryop_expression_node_t::Pointerof: return os << "pointerof"; - case unaryop_expression_node_t::Sizeof: return os << "sizeof"; - } - return os; -} - -void unary_op_expression_node::accept(visitor& visitor) const { - visitor.visit(*this); -} - -std::ostream& unary_op_expression_node::print(std::ostream& os) const { - if (m_node == nullptr) return os; - switch (m_type) { - case unaryop_expression_node_t::Positive: - case unaryop_expression_node_t::Negative: - case unaryop_expression_node_t::PrefixIncrement: - case unaryop_expression_node_t::PrefixDecrement: return os << '(' << m_type << *m_node << ')'; - case unaryop_expression_node_t::PostfixIncrement: - case unaryop_expression_node_t::PostfixDecrement: return os << '(' << *m_node << m_type << ')'; - case unaryop_expression_node_t::Pointerof: return os << "pointerof " << *m_node; - case unaryop_expression_node_t::Sizeof: return os << "sizeof " << *m_node; - } - return os; -} - -bool unary_op_expression_node::equal(const node& rhsNode) const { - const auto& rhs = dynamic_cast(rhsNode); - return expression_node::equal(rhsNode) && m_type == rhs.m_type && m_node == rhs.m_node; -} - -std::ostream& operator<<(std::ostream& os, binop_expression_node_t type) { - switch (type) { - default: - case binop_expression_node_t::None: return os; - case binop_expression_node_t::Add: return os << '+'; - case binop_expression_node_t::Sub: return os << '-'; - case binop_expression_node_t::Mul: return os << '*'; - case binop_expression_node_t::Div: return os << '/'; - case binop_expression_node_t::Mod: return os << '%'; - case binop_expression_node_t::Equal: return os << "=="; - case binop_expression_node_t::NotEqual: return os << "!="; - case binop_expression_node_t::LessThan: return os << '<'; - case binop_expression_node_t::GreaterThan: return os << '>'; - case binop_expression_node_t::LessEqual: return os << "<="; - case binop_expression_node_t::GreaterEqual: return os << ">="; - } -} - -void binary_op_expression_node::accept(visitor& visitor) const { - visitor.visit(*this); -} - -std::ostream& binary_op_expression_node::print(std::ostream& os) const { - if (m_type == binop_expression_node_t::None) return os; - return os << '(' << *m_lhs << ' ' << m_type << ' ' << *m_rhs << ')'; -} - -bool binary_op_expression_node::equal(const node& rhsNode) const { - 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; -} - -void var_assign_expression_node::accept(visitor& visitor) const { - visitor.visit(*this); -} - -std::ostream& var_assign_expression_node::print(std::ostream& os) const { - return os << '(' << *m_lhs << ' ' << m_compound << "= " << *m_rhs << ')'; -} - -bool var_assign_expression_node::equal(const node& rhsNode) const { - 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; -} - -void function_call_expression_node::accept(visitor& visitor) const { - visitor.visit(*this); -} - -std::ostream& function_call_expression_node::print(std::ostream& os) const { - os << *m_func << '('; - bool first = true; - for (const auto& arg : m_args) { - if (!first) os << ", "; - first = false; - os << *arg; - } - return os << ')'; -} - -bool function_call_expression_node::equal(const node& rhsNode) const { - const auto& rhs = dynamic_cast(rhsNode); - return expression_node::equal(rhsNode) && m_func == rhs.m_func && m_args == rhs.m_args; -} - -bool declaration_node::equal(const node& rhs) const { - return declaration_type() == dynamic_cast(rhs).declaration_type(); -} - -void function_declaration_node::accept(visitor& visitor) const { - visitor.visit(*this); -} - -std::ostream& function_declaration_node::print(std::ostream& os) const { - return os << "function " << p_name << " declaration"; -} - -bool function_declaration_node::equal(const node& rhs) const { - return declaration_node::equal(rhs) && p_name == dynamic_cast(rhs).p_name; -} - -void function_definition_node::accept(visitor& visitor) const { - visitor.visit(*this); -} - -std::ostream& function_definition_node::print(std::ostream& os) const { - function_declaration_node::print(os); - os << ":\n"; - for (const auto& entry : m_body.statements) - os << entry << '\n'; - return os << m_body.end << ": " << p_name << " end"; -} - -bool function_definition_node::equal(const node& rhs) const { - return function_declaration_node::equal(rhs) && m_body == dynamic_cast(rhs).m_body; -} - -bool statement_node::equal(const node& rhs) const { - return statement_type() == dynamic_cast(rhs).statement_type(); -} - -void return_statement_node::accept(visitor& visitor) const { - visitor.visit(*this); -} - -std::ostream& return_statement_node::print(std::ostream& os) const { - os << "return statement"; - if (m_value.has_value()) return os << ' ' << *m_value.value(); - return os; -} - -bool return_statement_node::equal(const node& rhs) const { - return statement_node::equal(rhs) && m_value == dynamic_cast(rhs).m_value; -} - -void if_statement_node::accept(visitor& visitor) const { - visitor.visit(*this); -} - -std::ostream& if_statement_node::print(std::ostream& os) const { - os << "if " << *m_cond << ", then:\n"; - os << m_then; - if (m_else.has_value()) os << *m_else.value(); - return os; -} - -bool if_statement_node::equal(const node& rhsNode) const { - 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; -} - -void compound_statement_node::accept(visitor& visitor) const { - visitor.visit(*this); -} - -std::ostream& compound_statement_node::print(std::ostream& os) const { - return os << m_body; -} - -bool compound_statement_node::equal(const node& rhs) const { - return statement_node::equal(rhs) && m_body == dynamic_cast(rhs).m_body; -} - -void while_statement_node::accept(visitor& visitor) const { - visitor.visit(*this); -} - -std::ostream& while_statement_node::print(std::ostream& os) const { - return os << m_body; -} - -bool while_statement_node::equal(const node& rhs) const { - return statement_node::equal(rhs) && m_body == dynamic_cast(rhs).m_body; -} - -void program_node::accept(visitor& visitor) const { - for (const auto& decl : m_declarations) { - decl->accept(visitor); - } -} - -std::ostream& program_node::print(std::ostream& os) const { - os << "program:"; - for (const auto& handle : m_declarations) { - os << '\n' << handle; - } - return os; -} - -bool program_node::equal(const node& rhs) const { - return m_declarations == dynamic_cast(rhs).m_declarations; -} - -std::ostream& operator<<(std::ostream& os, const body& body) { - os << "body:"; - for (const auto& stmt : body.statements) { - os << '\n' << stmt; - } - return os; -} - -} // namespace furc::ast diff --git a/furc/src/back/furvm.cpp b/furc/src/back/furvm.cpp deleted file mode 100644 index 0a10701..0000000 --- a/furc/src/back/furvm.cpp +++ /dev/null @@ -1,196 +0,0 @@ -#include "furc/back/furvm.hpp" - -#include "furlang/ir/function.hpp" -#include "furlang/ir/instruction.hpp" -#include "furvm/function.hpp" -#include "furvm/fwd.hpp" - -#include -#include - -namespace furc::back { - -furvm::mod furvm_generator::generate(furlang::ir::mod& mod) { - furvm::mod vmMod; - - for (const auto& function : mod.functions()) { - generate_function(vmMod, *function); - } - - return vmMod; -} - -void furvm_generator::generate_function(furvm::mod& mod, const furlang::ir::function& function) { - furvm::function_sig signature; // TODO: Complete - - switch (function.type()) { - case furlang::ir::function_t::Normal: { - if (function.access() == furlang::ir::function_access_t::Public) - mod.emplace_function(function.name(), std::move(signature), mod.bytecode().size()).dispatch(); - else - mod.emplace_function(std::move(signature), mod.bytecode().size()).dispatch(); - - function_context ctx; - for (furlang::ir::block_index idx = 0; idx < function.blocks().size(); ++idx) { - if (auto it = ctx.incompleteJumps.find(idx); it != ctx.incompleteJumps.end()) { - for (std::size_t offset : it->second) { - mod.bytecode()[offset] = mod.bytecode().size() - offset - 1; - } - ctx.incompleteJumps.erase(it); - } - - ctx.blockOffsets[idx] = mod.bytecode().size(); - for (const auto& instr : function.blocks()[idx]->instructions()) - generate_instruction(mod, ctx, *instr); - generate_instruction(mod, ctx, *function.blocks()[idx]->exit()); - } - } break; - case furlang::ir::function_t::Import: { - throw std::runtime_error("unimplemented"); - // mod.emplace_function_private(function.name(), function.param_count(), mod.bytecode().size()).dispatch(); - } break; - case furlang::ir::function_t::Native: { - if (function.access() == furlang::ir::function_access_t::Public) - mod.emplace_function(function.name(), std::move(signature), function.name()).dispatch(); - else - mod.emplace_function(std::move(signature), function.name()).dispatch(); - } break; - } -} - -static inline furvm::instruction_t op_type(furlang::ir::instruction_t type) { - switch (type) { - // Unary - case furlang::ir::instruction_t::Pointerof: return furvm::instruction_t::Pointerof; - case furlang::ir::instruction_t::Sizeof: return furvm::instruction_t::Sizeof; - - // Binary - case furlang::ir::instruction_t::Add: return furvm::instruction_t::Add; - case furlang::ir::instruction_t::Sub: return furvm::instruction_t::Sub; - case furlang::ir::instruction_t::Mul: return furvm::instruction_t::Mul; - case furlang::ir::instruction_t::Div: return furvm::instruction_t::Div; - case furlang::ir::instruction_t::Mod: return furvm::instruction_t::Mod; - case furlang::ir::instruction_t::Eq: return furvm::instruction_t::Equals; - case furlang::ir::instruction_t::NotEq: return furvm::instruction_t::NotEquals; - case furlang::ir::instruction_t::LessThan: return furvm::instruction_t::LessThan; - case furlang::ir::instruction_t::GreaterThan: return furvm::instruction_t::GreaterThan; - case furlang::ir::instruction_t::LessEq: return furvm::instruction_t::LessEqual; - case furlang::ir::instruction_t::GreaterEq: return furvm::instruction_t::GreaterEqual; - - default: throw std::runtime_error("unreachable"); - } -} - -void furvm_generator::generate_instruction(furvm::mod& mod, - function_context& ctx, - const furlang::ir::instruction& instr) { - for (const auto& operand : instr.sources()) - generate_operand(mod, ctx, *operand); - - switch (instr.type()) { - case furlang::ir::instruction_t::Assign: { - if (ctx.variables.find(instr.destination().reg()) == ctx.variables.end()) { - ctx.variables[instr.destination().reg()] = ctx.variableCounter++; - } - auto var = ctx.variables[instr.destination().reg()]; - mod.bytecode().push_back(static_cast(furvm::instruction_t::Store)); - mod.bytecode().push_back((var >> 0) & 0xFF); - mod.bytecode().push_back((var >> 8) & 0xFF); - static_assert(sizeof(var) == 2, "sizeof(furvm::variable_t) has changed"); - } break; - case furlang::ir::instruction_t::Add: - case furlang::ir::instruction_t::Sub: - case furlang::ir::instruction_t::Mul: - case furlang::ir::instruction_t::Div: - case furlang::ir::instruction_t::Mod: - case furlang::ir::instruction_t::Eq: - case furlang::ir::instruction_t::NotEq: - case furlang::ir::instruction_t::LessThan: - case furlang::ir::instruction_t::GreaterThan: - case furlang::ir::instruction_t::LessEq: - case furlang::ir::instruction_t::GreaterEq: { - mod.bytecode().push_back(static_cast(op_type(instr.type()))); - - if (ctx.variables.find(instr.destination().reg()) == ctx.variables.end()) { - ctx.variables[instr.destination().reg()] = ctx.variableCounter++; - } - auto var = ctx.variables[instr.destination().reg()]; - mod.bytecode().push_back(static_cast(furvm::instruction_t::Store)); - mod.bytecode().push_back((var >> 0) & 0xFF); - mod.bytecode().push_back((var >> 8) & 0xFF); - static_assert(sizeof(var) == 2, "sizeof(furvm::variable_t) has changed"); - } break; - case furlang::ir::instruction_t::Pointerof: - case furlang::ir::instruction_t::Sizeof: { - mod.bytecode().push_back(static_cast(op_type(instr.type()))); - - if (ctx.variables.find(instr.destination().reg()) == ctx.variables.end()) { - ctx.variables[instr.destination().reg()] = ctx.variableCounter++; - } - auto var = ctx.variables[instr.destination().reg()]; - mod.bytecode().push_back(static_cast(furvm::instruction_t::Store)); - mod.bytecode().push_back((var >> 0) & 0xFF); - mod.bytecode().push_back((var >> 8) & 0xFF); - static_assert(sizeof(var) == 2, "sizeof(furvm::variable_t) has changed"); - } break; - case furlang::ir::instruction_t::Branch: { - const auto& branch = dynamic_cast(instr); - generate_jump(mod, ctx, branch.block(), false); - } break; - case furlang::ir::instruction_t::BranchCond: { - const auto& branch = dynamic_cast(instr); - generate_jump(mod, ctx, branch.if_block(), true); - generate_jump(mod, ctx, branch.else_block(), false); - } break; - case furlang::ir::instruction_t::Return: { - mod.bytecode().push_back(static_cast(furvm::instruction_t::Return)); - } break; - case furlang::ir::instruction_t::Call: { - const auto& call = dynamic_cast(instr); - - // TODO: Implement a queue for unknown functions - furvm::function_id func = mod.function_at(call.name(), furvm::function_sig{}).id(); // TODO: Complete - mod.bytecode().push_back(static_cast(furvm::instruction_t::Call)); - mod.bytecode().push_back((func >> 0) & 0xFF); - mod.bytecode().push_back((func >> 8) & 0xFF); - } break; - case furlang::ir::instruction_t::Alloca: throw std::runtime_error("unimplemented instruction"); - case furlang::ir::instruction_t::Phi: throw std::runtime_error("unreachable"); - } -} - -void furvm_generator::generate_operand(furvm::mod& mod, function_context& ctx, const furlang::ir::operand& operand) { - switch (operand.type()) { - case furlang::ir::operand_t::Register: { - if (ctx.variables.find(operand.reg()) == ctx.variables.end()) throw std::runtime_error("unregistered register"); - auto var = ctx.variables[operand.reg()]; - mod.bytecode().push_back(static_cast(furvm::instruction_t::Load)); - mod.bytecode().push_back((var >> 0) & 0xFF); - mod.bytecode().push_back((var >> 8) & 0xFF); - static_assert(sizeof(var) == 2, "sizeof(furvm::variable_t) has changed"); - } break; - case furlang::ir::operand_t::Integer: { - mod.bytecode().push_back(static_cast(furvm::instruction_t::PushS32)); - mod.bytecode().push_back(operand.integer()); - } break; - case furlang::ir::operand_t::Variable: - case furlang::ir::operand_t::String: throw std::runtime_error("unimplemented operand"); - case furlang::ir::operand_t::None: throw std::runtime_error("unreachable"); - } -} - -void furvm_generator::generate_jump(furvm::mod& mod, - function_context& ctx, - furlang::ir::block_index block, - bool conditional) { - mod.bytecode().push_back( - static_cast(conditional ? furvm::instruction_t::JumpNotZero : furvm::instruction_t::Jump)); - if (auto it = ctx.blockOffsets.find(block); it != ctx.blockOffsets.end()) { - mod.bytecode().push_back(it->second - mod.bytecode().size() - 1); - } else { - ctx.incompleteJumps[block].push_back(mod.bytecode().size()); - mod.bytecode().push_back(0); - } -} - -} // namespace furc::back diff --git a/furc/src/front/ir_generator.cpp b/furc/src/front/ir_generator.cpp deleted file mode 100644 index 386ec4f..0000000 --- a/furc/src/front/ir_generator.cpp +++ /dev/null @@ -1,232 +0,0 @@ -#include "furc/front/ir_generator.hpp" - -#include "furc/ast/declaration.hpp" // IWYU pragma: keep -#include "furc/ast/expression.hpp" // IWYU pragma: keep -#include "furc/ast/literal.hpp" // IWYU pragma: keep -#include "furc/ast/statement.hpp" // IWYU pragma: keep -#include "furlang/ir/function.hpp" -#include "furlang/ir/instruction.hpp" -#include "furlang/ir/operand.hpp" - -#include -#include -#include -#include - -namespace furc::front { - -namespace { -namespace ir = furlang::ir; -} - -void ir_generator::visit(const ast::function_definition_node& funcDef) { - furlang::ir::function_access_t access = (funcDef.access() == ast::declaration_access_t::Public) - ? furlang::ir::function_access_t::Public - : furlang::ir::function_access_t::Private; - - m_currentFunction = std::make_unique(std::string(funcDef.name()), access, 0); - - push_block(); - for (const auto& stmt : funcDef.body().statements) { - stmt.value()->accept(*this); - } - - m_currentBlock->emplace(); - - m_module.push(std::move(m_currentFunction)); -} - -void ir_generator::visit(const ast::function_declaration_node& funcDecl) { - if (funcDecl.type() == ast::function_declaration_node_t::Normal) return; - - furlang::ir::function_t type = funcDecl.type() == ast::function_declaration_node_t::Import - ? furlang::ir::function_t::Import - : furlang::ir::function_t::Native; - - furlang::ir::function_access_t access = (funcDecl.access() == ast::declaration_access_t::Public) - ? furlang::ir::function_access_t::Public - : furlang::ir::function_access_t::Private; - - m_module.push( - std::make_unique(std::string(funcDecl.name()), access, funcDecl.params().size(), type)); -} - -void ir_generator::visit(const ast::return_statement_node& returnStmt) { - if (returnStmt.value().has_value()) { - returnStmt.value().value()->accept(*this); - push(ir::operand::new_reg(m_registerCounter - 1)); - } else { - push(); - } -} - -void ir_generator::visit(const ast::if_statement_node& node) { - node.cond()->accept(*this); - ir_register cond = m_registerCounter - 1; - push(ir::operand::new_reg(cond), - m_currentFunction->blocks().size(), - m_currentFunction->blocks().size() + 1); - - push_block(); // then block - node.then()->accept(*this); - if (node.elze().has_value()) { - m_currentBlock->emplace(m_currentFunction->blocks().size() + 1); - - push_block(); // else block - node.elze().value()->accept(*this); - } - m_currentBlock->emplace(m_currentFunction->blocks().size()); - - push_block(); // merge block -} - -void ir_generator::visit(const ast::while_statement_node& node) { - node.condition()->accept(*this); - ir_register cond = m_registerCounter - 1; - std::shared_ptr entry = m_currentBlock; - ir::block_index headerIdx = m_currentFunction->blocks().size(); - - push_block(false); // loop header - push(m_currentFunction->blocks().size()); - - push_block(); // loop condition - node.condition()->accept(*this); - std::shared_ptr condBlock = m_currentBlock; - ir_register cond2 = m_registerCounter - 1; - - push_block(false); // loop body - node.body()->accept(*this); - push(headerIdx); - - entry->emplace(ir::operand::new_reg(cond), - headerIdx, - m_currentFunction->blocks().size()); - condBlock->emplace(ir::operand::new_reg(cond2), - m_currentFunction->blocks().size() - 1, - m_currentFunction->blocks().size()); - push_block(); // merge block -} - -void ir_generator::visit(const ast::compound_statement_node& node) { - for (const auto& stmt : node.body().statements) { - stmt.value()->accept(*this); - } -} - -void ir_generator::visit(const ast::string_literal_node& node) { - 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()), - ir::operand::new_reg(m_registerCounter++)); -} - -void ir_generator::visit(const ast::var_read_expression_node& node) { - if (auto it = m_variables.find(node.get_name()); it != m_variables.end()) { - push(ir::operand::new_reg(it->second), - ir::operand::new_reg(m_registerCounter++)); - } else { - throw std::runtime_error("unknown variable"); - } -} - -static inline furlang::ir::instruction_t unary_op_instruction_t(ast::unaryop_expression_node_t type) { - switch (type) { - case ast::unaryop_expression_node_t::Pointerof: return furlang::ir::instruction_t::Pointerof; - case ast::unaryop_expression_node_t::Sizeof: return furlang::ir::instruction_t::Sizeof; - default: throw std::runtime_error("unimplemented"); - } -} - -void ir_generator::visit(const ast::unary_op_expression_node& node) { - node.get_node()->accept(*this); - ir_register src = m_registerCounter - 1; - ir_register dst = m_registerCounter++; - push(unary_op_instruction_t(node.type()), - ir::operand::new_reg(src), - ir::operand::new_reg(dst)); -} - -static inline furlang::ir::instruction_t binary_op_instruction_t(ast::binop_expression_node_t type) { - switch (type) { - case ast::binop_expression_node_t::Add: return furlang::ir::instruction_t::Add; - case ast::binop_expression_node_t::Sub: return furlang::ir::instruction_t::Sub; - case ast::binop_expression_node_t::Mul: return furlang::ir::instruction_t::Mul; - case ast::binop_expression_node_t::Div: return furlang::ir::instruction_t::Div; - case ast::binop_expression_node_t::Mod: return furlang::ir::instruction_t::Mod; - case ast::binop_expression_node_t::Equal: return furlang::ir::instruction_t::Eq; - case ast::binop_expression_node_t::NotEqual: return furlang::ir::instruction_t::NotEq; - case ast::binop_expression_node_t::LessThan: return furlang::ir::instruction_t::LessThan; - case ast::binop_expression_node_t::GreaterThan: return furlang::ir::instruction_t::GreaterThan; - case ast::binop_expression_node_t::LessEqual: return furlang::ir::instruction_t::LessEq; - case ast::binop_expression_node_t::GreaterEqual: return furlang::ir::instruction_t::GreaterEq; - case ast::binop_expression_node_t::None: - default: throw std::runtime_error("unreachable"); - } -} - -void ir_generator::visit(const ast::binary_op_expression_node& node) { - node.lhs()->accept(*this); - ir_register lhs = m_registerCounter - 1; - node.rhs()->accept(*this); - ir_register rhs = m_registerCounter - 1; - ir_register dst = m_registerCounter++; - push(binary_op_instruction_t(node.type()), - ir::operand::new_reg(lhs), - ir::operand::new_reg(rhs), - ir::operand::new_reg(dst)); -} - -void ir_generator::visit(const ast::var_assign_expression_node& node) { - node.rhs()->accept(*this); - ir_register rhs = m_registerCounter - 1; - assert(node.lhs()->expression_type() == ast::expression_node_t::VarRead); - auto lhs = std::dynamic_pointer_cast(node.lhs()); - - ir_register reg = m_registerCounter++; - - auto compound = node.compound(); - if (compound != ast::binop_expression_node_t::None) { - push(binary_op_instruction_t(compound), - ir::operand::new_reg(reg), - ir::operand::new_reg(rhs), - ir::operand::new_reg(reg)); - } else { - push(ir::operand::new_reg(rhs), ir::operand::new_reg(reg)); - } - - if (auto it = m_variables.find(lhs->get_name()); it != m_variables.end()) { - push(ir::operand::new_reg(reg), ir::operand::new_reg(it->second)); - } else { - m_variables[lhs->get_name()] = reg; - } -} - -void ir_generator::visit(const ast::function_call_expression_node& node) { - std::vector args; - args.reserve(node.args().size()); - for (const auto& arg : node.args()) { - arg->accept(*this); - args.push_back(ir::operand::new_reg(m_registerCounter - 1)); - } - if (node.func()->expression_type() != ast::expression_node_t::VarRead) - throw std::runtime_error("invalid function call left-hand-side expression"); - - push(dynamic_cast(*node.func()).get_name(), - ir::operand::new_reg(m_registerCounter++), - std::move(args)); -} - -furlang::ir::block_index ir_generator::push_block(bool validate) { - if (validate && !m_currentFunction->blocks().empty() && !m_currentFunction->blocks().back()->has_exit()) { - throw std::runtime_error( - "block " + std::to_string(m_currentFunction->blocks().size() - 1) + " is lacking an exit"); - } - ir::block_index index = m_currentFunction->blocks().size(); - m_currentBlock = m_currentFunction->push(); - return index; -} - -} // namespace furc::front diff --git a/furc/src/front/lexer.cpp b/furc/src/front/lexer.cpp deleted file mode 100644 index 1ba946f..0000000 --- a/furc/src/front/lexer.cpp +++ /dev/null @@ -1,200 +0,0 @@ -#include "furc/front/lexer.hpp" - -#include "furc/front/token.hpp" - -#include -#include -#include -#include -#include - -namespace furc::front { - -using namespace std::string_literals; - -lexer::lexer(std::string_view filename, std::string_view content) - : m_filename(filename), m_content(content) {} - -token_r lexer::next_token() { - skip_spaces(); - while (m_cursor + 2 <= m_content.size() && m_content[m_cursor] == '/') { - if (m_content[m_cursor + 1] == '/') { - m_cursor += 2; - while (m_content[m_cursor] != '\n') { - next(); - } - } else if (m_content[m_cursor + 1] == '*') { - m_cursor += 2; - while (m_cursor + 2 < m_content.size()) { - if (m_content[m_cursor + 1] == '*') { - next(); - } else if (m_content[m_cursor + 0] != '*' || m_content[m_cursor + 1] != '/') { - next(); - next(); - } else { - break; - } - } - if (m_cursor + 2 >= m_content.size()) { - next(); - return token_r( - token_error{ current_location(), token_error_t::UnexpectedEof, "before enclosing `*/`" }); - } - m_cursor += 2; - } else { - break; - } - skip_spaces(); - } - - location location = current_location(); - - switch (get()) { - case '"': { - std::size_t begin = ++m_cursor; - while (m_cursor < m_content.size() && m_content[m_cursor] != '"') - ++m_cursor; - if (m_cursor >= m_content.size()) { - return token_r(token_error{ current_location(), token_error_t::UnexpectedEof, "before enclosing '\"'" }); - } - ++m_cursor; - - return { location, token_t::String, m_content.substr(begin, m_cursor - begin - 1) }; - } - case std::char_traits::eof(): return token_r(token_error{ current_location(), token_error_t::EndOfFile }); - default: { - if (std::isdigit(get()) != 0) { - integer_token integer = 0; - integer_token max = std::numeric_limits::max(); - integer_token upperBound = max / 10; - - std::size_t start = m_cursor; - while (std::isdigit(get()) != 0) { - integer_token digit = get() - '0'; - - if (integer > upperBound || integer == upperBound && (integer - upperBound + digit) > (max % 10)) { - while (std::isdigit(get()) != 0) - ++m_cursor; - return token_r(token_error{ location, - token_error_t::IntegerOverflow, - std::string(m_content.substr(start, m_cursor - start)) }); - } - integer *= 10; - integer += digit; - ++m_cursor; - } - - return { location, integer }; - } - - if (std::isalnum(get()) != 0 || get() == '_') { - std::size_t start = m_cursor++; - while (std::isalnum(get()) != 0 || get() == '_') - next(); - - std::string_view value = m_content.substr(start, m_cursor - start); - - static std::unordered_map s_keywords = { - { "func", keyword_token::Func }, - { "return", keyword_token::Return }, - { "if", keyword_token::If }, - { "else", keyword_token::Else }, - { "while", keyword_token::While }, - { "import", keyword_token::Import }, - { "native", keyword_token::Native }, - { "public", keyword_token::Public }, - { "private", keyword_token::Private }, - { "pointerof", keyword_token::Pointerof }, - { "sizeof", keyword_token::Sizeof }, - { "int32", keyword_token::Int32 }, - }; - - if (auto it = s_keywords.find(value); it != s_keywords.end()) return { location, it->second }; - return { location, token_t::Identifier, value }; - } - - struct compare { - bool operator()(const std::string_view& lhs, const std::string_view& rhs) const { - if (lhs.size() != rhs.size()) return lhs.size() > rhs.size(); - return lhs < rhs; - } - }; - - static std::map s_tokens = { - { "(", token_t::LParen }, - { ")", token_t::RParen }, - { "{", token_t::LBrace }, - { "}", token_t::RBrace }, - { "[", token_t::LBracket }, - { "]", token_t::RBracket }, - { ";", token_t::Semicolon }, - { ":", token_t::Colon }, - { ",", token_t::Comma }, - { ".", token_t::Dot }, - { "+", token_t::Plus }, - { "-", token_t::Minus }, - { "*", token_t::Star }, - { "/", token_t::Slash }, - { "%", token_t::Percent }, - { "++", token_t::DPlus }, - { "--", token_t::DMinus }, - { "=", token_t::Eq }, - { "+=", token_t::PlusEq }, - { "-=", token_t::MinusEq }, - { "*=", token_t::StarEq }, - { "/=", token_t::SlashEq }, - { "%=", token_t::PercentEq }, - { "==", token_t::DEq }, - { "!=", token_t::NotEq }, - { "<", token_t::LessThan }, - { ">", token_t::GreaterThan }, - { "<=", token_t::LessEq }, - { ">=", token_t::GreaterEq }, - { "->", token_t::SlimArrow }, - { "=>", token_t::FatArrow }, - }; - - token_t type = token_t::None; - std::size_t length = 1; - while (m_cursor + length <= m_content.size()) { - auto it = s_tokens.find(m_content.substr(m_cursor, length)); - if (it == s_tokens.end()) break; - type = it->second; - ++length; - } - if (type != token_t::None) { - m_cursor += length - 1; - return { location, type }; - } - - return token_r( - token_error{ location, token_error_t::UnexpectedCharacter, std::string(m_content.substr(m_cursor, 1)) }); - } - } -} - -void lexer::next() { - if (m_cursor >= m_content.size()) return; - char ch = get(); - ++m_cursor; - if (ch == '\n') { - ++m_row; - m_lineStart = m_cursor; - } -} - -char lexer::get(std::size_t offset) const { - if (m_cursor + offset < m_content.size()) return m_content[m_cursor + offset]; - return std::char_traits::eof(); -} - -void lexer::skip_spaces() { - while (std::isspace(get()) != 0) - next(); -} - -location lexer::current_location() { - return { m_filename, m_row, m_cursor - m_lineStart }; -} - -} // namespace furc::front diff --git a/furc/src/front/parser.cpp b/furc/src/front/parser.cpp deleted file mode 100644 index 3c405d1..0000000 --- a/furc/src/front/parser.cpp +++ /dev/null @@ -1,587 +0,0 @@ -#include "furc/front/parser.hpp" - -#include "furc/ast/declaration.hpp" // IWYU pragma: keep -#include "furc/ast/expression.hpp" // IWYU pragma: keep -#include "furc/ast/fwd.hpp" -#include "furc/ast/literal.hpp" // IWYU pragma: keep -#include "furc/ast/program.hpp" // IWYU pragma: keep -#include "furc/ast/statement.hpp" // IWYU pragma: keep -#include "furc/front/token.hpp" - -#include -#include -#include -#include -#include - -namespace furc::front { - -using namespace std::string_literals; - -parser::parser(furlang::arena& arena, std::string_view filename, std::string_view content) - : m_filename(filename), m_content(content), m_lexer(m_filename, m_content), m_arena(&arena) {} - -parser::parser(furlang::arena& arena, std::string_view filename) - : m_filename(filename), m_arena(&arena) { - std::ifstream file(m_filename, std::ios_base::binary | std::ios_base::ate); - if (!file.is_open()) throw std::runtime_error("failed to open file "s.append(m_filename)); - std::streampos size = file.tellg(); - file.seekg(0); - - m_content.resize(size); - file.read(m_content.data(), size); - m_lexer = { filename, m_content }; -} - -ast::program_node_r parser::parse() & { - auto program = m_arena->allocate_shared(location{ m_filename }); - - while (peek_token().has_value()) { - auto decl = parse_declaration(); - if (decl.has_error()) return ast::program_node_r(ast::error{ decl.error().location }); - program->push(std::move(decl.value())); - } - - return program; -} - -ast::type_r parser::parse_type() { - auto token = eat_token(token_t::Keyword); - if (token.has_error() || token.value()->keyword != keyword_token::Int32) - return ast::type_r(ast::error{ token.error().location }); - return ast::type("" + token.value()->keyword); -} - -ast::declaration_node_r parser::parse_declaration() { - const auto& first = peek_token(); - if (first.has_error()) return ast::declaration_node_r(ast::error{ first.error().location }); - switch (first->type) { - case token_t::Keyword: { - token firstToken = *first; - - ast::declaration_access_t accessOverride = ast::declaration_access_t::Implicit; - switch ((*first)->keyword) { - default: break; - case keyword_token::Public: - case keyword_token::Private: { - if ((*first)->keyword == keyword_token::Public) accessOverride = ast::declaration_access_t::Public; - if ((*first)->keyword == keyword_token::Private) accessOverride = ast::declaration_access_t::Private; - auto kw = eat_token(token_t::Keyword); - if (kw.has_error()) return ast::declaration_node_r(ast::error{ kw.error().location }); - firstToken = *kw; - } break; - } - - ast::function_declaration_node_t funcDeclType{}; - - auto kw = next_token(); - if (kw.has_error()) return ast::declaration_node_r(ast::error{ kw.error().location }); - firstToken = *kw; - switch (firstToken->keyword) { - case keyword_token::Import: - case keyword_token::Native: { - funcDeclType = (firstToken->keyword == keyword_token::Import) ? ast::function_declaration_node_t::Import - : ast::function_declaration_node_t::Native; - - auto kw = eat_token(token_t::Keyword); - if (kw.has_error()) return ast::declaration_node_r(ast::error{ kw.error().location }); - firstToken = *kw; - if (firstToken.value.keyword != keyword_token::Func) - return ast::declaration_node_r(ast::error{ firstToken.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; - } - - auto access = (funcDeclType == ast::function_declaration_node_t::Import) - ? ast::declaration_access_t::Private - : accessOverride; - if (access == ast::declaration_access_t::Implicit) access = ast::declaration_access_t::Public; - if (!ast::same_access(accessOverride, access)) return ast::declaration_node_r(ast::error{ tok->location }); - - 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(firstToken.location, - access, - 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(firstToken.location, - access, - name->value.string, - std::move(returnType), - std::move(params), - funcDeclType); - } - default: return ast::declaration_node_r(ast::error{ tok->location }); - } - } - default: return ast::declaration_node_r(ast::error{ firstToken.location }); - } - } - case token_t::None: - case token_t::Identifier: - case token_t::Integer: - case token_t::LParen: - case token_t::RParen: - case token_t::LBrace: - case token_t::RBrace: - case token_t::LBracket: - case token_t::RBracket: - case token_t::Semicolon: - case token_t::Colon: - default: { - return ast::declaration_node_r(ast::error{ first->location }); - } - } -} - -ast::statement_node_r parser::parse_statement() { - const auto& tok = peek_token(); - if (tok.has_error()) return ast::statement_node_r(ast::error{ tok.error().location }); - auto location = tok->location; - switch (tok->type) { - case token_t::Keyword: { - switch (tok->value.keyword) { - case keyword_token::Return: { - auto tok = next_token(); - if (peek_token()->type == token_t::Semicolon) { - next_token(); - 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(location, std::move(value.value())); - } - case keyword_token::If: { - auto tok = next_token(); - auto err = eat_token(token_t::LParen); - if (err.has_error()) return ast::statement_node_r(ast::error{ err.error().location }); - - auto cond = parse_expression(); - - err = eat_token(token_t::RParen); - if (err.has_error()) return ast::statement_node_r(ast::error{ err.error().location }); - - auto then = parse_statement(); - if (then.has_error()) return ast::statement_node_r(ast::error{ then.error().location }); - - if (peek_token().has_value() && peek_token()->type == token_t::Keyword && - peek_token()->value.keyword == keyword_token::Else) { - next_token(); - - auto elseBody = parse_statement(); - if (elseBody.has_error()) return ast::statement_node_r(ast::error{ elseBody.error().location }); - return m_arena->allocate_shared(location, - std::move(cond.value()), - std::move(then.value()), - std::move(elseBody.value())); - } - - return m_arena->allocate_shared(location, - std::move(cond.value()), - std::move(then.value())); - } - case keyword_token::While: { - auto tok = next_token(); - auto err = eat_token(token_t::LParen); - if (err.has_error()) return ast::statement_node_r(ast::error{ err.error().location }); - - auto cond = parse_expression(); - if (cond.has_error()) return ast::statement_node_r(ast::error{ cond.error().location }); - - err = eat_token(token_t::RParen); - if (err.has_error()) return ast::statement_node_r(ast::error{ err.error().location }); - - auto body = parse_statement(); - if (body.has_error()) return ast::statement_node_r(ast::error{ body.error().location }); - - return m_arena->allocate_shared(location, - std::move(cond.value()), - std::move(body.value())); - } - case keyword_token::None: - case keyword_token::Func: - default: break; - } - } - case token_t::LBrace: { - auto body = parse_body(); - if (body.has_error()) return ast::statement_node_r(ast::error{ body.error().location }); - return m_arena->allocate_shared(location, std::move(body.value())); - } - default: break; - } - - auto declaration = parse_declaration(); - if (declaration.has_value()) return std::move(*declaration); - auto expression = parse_expression(); - if (expression.has_value()) { - auto semi = eat_token(token_t::Semicolon); - if (semi.has_error()) return ast::statement_node_r(ast::error{ semi.error().location }); - return std::move(*expression); - } - - auto token = next_token(); - return ast::statement_node_r(ast::error{ token->location }); -} - -ast::expression_node_r parser::parse_expression(std::uint32_t precedence) { - auto expr = parse_expression_unary(precedence); - if (expr.has_error()) { - return ast::expression_node_r(ast::error{ expr.error().location }); - } - return parse_expression_rhs(std::move(expr.value()), precedence); -} - -ast::expression_node_r parser::parse_expression_primary() { - const auto& tok = peek_token(); - switch (tok->type) { - 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->location, (*tok)->string); - } - case token_t::LParen: { - auto tok = next_token(); - auto node = parse_expression(); - auto err = eat_token(token_t::RParen); - 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: { - return ast::expression_node_r(ast::error{ tok->location }); - } - } -} - -struct unaryop_info { - ast::unaryop_expression_node_t type; - std::uint32_t precedence; -}; - -static inline std::optional get_unaryop_info(const token_r& token) { - static std::unordered_map s_prefixes = { - { token_t::Plus, unaryop_info{ ast::unaryop_expression_node_t::Positive, 2 } }, - { token_t::Minus, unaryop_info{ ast::unaryop_expression_node_t::Negative, 2 } }, - { token_t::DPlus, unaryop_info{ ast::unaryop_expression_node_t::PrefixIncrement, 2 } }, - { token_t::DMinus, unaryop_info{ ast::unaryop_expression_node_t::PrefixDecrement, 2 } }, - }; - static std::unordered_map s_keywords = { - { keyword_token::Pointerof, unaryop_info{ ast::unaryop_expression_node_t::Pointerof, 2 } }, - { keyword_token::Sizeof, unaryop_info{ ast::unaryop_expression_node_t::Sizeof, 2 } }, - }; - - if (token->type == token_t::Keyword) { - auto it = s_keywords.find(token->value.keyword); - if (it == s_keywords.end()) return {}; - return it->second; - } - - auto it = s_prefixes.find(token->type); - if (it == s_prefixes.end()) return {}; - return it->second; -} - -ast::expression_node_r parser::parse_expression_unary(std::uint32_t precedence) { - std::shared_ptr result; - while (true) { - auto opt = get_unaryop_info(peek_token()); - if (!opt.has_value()) break; - unaryop_info current = opt.value(); - if (current.precedence >= precedence) break; - auto token = next_token(); - - ast::expression_node_p expression; - - opt = get_unaryop_info(peek_token()); - if (opt.has_value()) { - auto next = opt.value(); - auto expr = parse_expression_unary(current.precedence + 1); - if (expr.has_error()) { - return ast::expression_node_r(ast::error{ expr.error().location }); - } - expression = std::move(std::move(expr.value())); - } - - result = m_arena->allocate_shared(token->location, - current.type, - std::move(expression)); - } - - if (result == nullptr) return parse_expression_primary(); - if (result->get_node() == nullptr) { - auto expr = parse_expression_primary(); - if (expr.has_error()) { - return ast::expression_node_r(ast::error{ expr.error().location }); - } - result->set_node(std::move(std::move(expr.value()))); - } - return result; -} - -enum class associativity { - Left, - Right, -}; - -enum class rhsop_info_t { - Unaryop, - Binop, - Assignment, - FuncCall, -}; - -struct rhsop_info { - rhsop_info_t type; - std::uint32_t precedence; - associativity associativity; - union { - ast::unaryop_expression_node_t unary; - ast::binop_expression_node_t binary; - ast::binop_expression_node_t assignment; - }; - - bool has_rhs() const { return type == rhsop_info_t::Binop || type == rhsop_info_t::Assignment; } - - static rhsop_info create(ast::unaryop_expression_node_t type, std::uint32_t precedence) { - rhsop_info info{}; - info.type = rhsop_info_t::Unaryop; - info.precedence = precedence; - info.associativity = associativity::Left; - info.unary = type; - return info; - } - - static rhsop_info create(ast::binop_expression_node_t type, - std::uint32_t precedence, - enum associativity associativity) { - rhsop_info info{}; - info.type = rhsop_info_t::Binop; - info.precedence = precedence; - info.associativity = associativity; - info.binary = type; - return info; - } - - static rhsop_info create(ast::binop_expression_node_t compound = ast::binop_expression_node_t::None) { - rhsop_info info{}; - info.type = rhsop_info_t::Assignment; - info.precedence = 14; - info.associativity = associativity::Right; - info.assignment = compound; - return info; - } - - static rhsop_info create_function_call() { - rhsop_info info{}; - info.type = rhsop_info_t::FuncCall; - info.precedence = 1; - info.associativity = associativity::Left; - return info; - } -}; - -ast::expression_node_r parser::parse_expression_rhs(ast::expression_node_p&& init, std::uint32_t precedence) { - static std::unordered_map s_rhsops = { - { token_t::Plus, rhsop_info::create(ast::binop_expression_node_t::Add, 5, associativity::Left) }, - { token_t::Minus, rhsop_info::create(ast::binop_expression_node_t::Sub, 5, associativity::Left) }, - { token_t::Star, rhsop_info::create(ast::binop_expression_node_t::Mul, 4, associativity::Left) }, - { token_t::Slash, rhsop_info::create(ast::binop_expression_node_t::Div, 4, associativity::Left) }, - { token_t::Percent, rhsop_info::create(ast::binop_expression_node_t::Mod, 5, associativity::Left) }, - { token_t::DPlus, rhsop_info::create(ast::unaryop_expression_node_t::PostfixIncrement, 1) }, - { token_t::DMinus, rhsop_info::create(ast::unaryop_expression_node_t::PostfixDecrement, 1) }, - { token_t::DMinus, rhsop_info::create(ast::unaryop_expression_node_t::PostfixDecrement, 1) }, - { token_t::Eq, rhsop_info::create() }, - { token_t::PlusEq, rhsop_info::create(ast::binop_expression_node_t::Add) }, - { token_t::MinusEq, rhsop_info::create(ast::binop_expression_node_t::Sub) }, - { token_t::StarEq, rhsop_info::create(ast::binop_expression_node_t::Mul) }, - { token_t::SlashEq, rhsop_info::create(ast::binop_expression_node_t::Div) }, - { token_t::PercentEq, rhsop_info::create(ast::binop_expression_node_t::Mod) }, - { token_t::DEq, rhsop_info::create(ast::binop_expression_node_t::Equal, 10, associativity::Left) }, - { token_t::NotEq, rhsop_info::create(ast::binop_expression_node_t::NotEqual, 10, associativity::Left) }, - { token_t::LessThan, rhsop_info::create(ast::binop_expression_node_t::LessThan, 9, associativity::Left) }, - { token_t::GreaterThan, rhsop_info::create(ast::binop_expression_node_t::GreaterThan, 9, associativity::Left) }, - { token_t::LessEq, rhsop_info::create(ast::binop_expression_node_t::LessEqual, 9, associativity::Left) }, - { token_t::GreaterEq, rhsop_info::create(ast::binop_expression_node_t::GreaterEqual, 9, associativity::Left) }, - { token_t::LParen, rhsop_info::create_function_call() }, - }; - - ast::expression_node_p lhs = std::move(init); - while (peek_token().has_value()) { - auto it = s_rhsops.find(peek_token()->type); - if (it == s_rhsops.end()) return lhs; - - rhsop_info current = it->second; - if (current.precedence >= precedence) return lhs; - auto opToken = next_token(); - - ast::expression_node_p rhs; - std::vector params; - if (current.has_rhs()) { - auto expr = parse_expression_unary(current.precedence + 1); // unary prefix is always right-associative - if (expr.has_error()) { - return ast::expression_node_r(ast::error{ expr.error().location }); - } - rhs = std::move(expr.value()); - } else if (current.type == rhsop_info_t::FuncCall && peek_token().has_value()) { - if (peek_token()->type != token_t::RParen) { - while (true) { - auto expr = parse_expression_unary(16); - if (expr.has_error()) { - return ast::expression_node_r(ast::error{ expr.error().location }); - } - params.emplace_back(std::move(expr.value())); - - if (eat_token(token_t::Comma).has_error()) break; - } - } - auto enclosing = eat_token(token_t::RParen); - if (enclosing.has_error()) return ast::expression_node_r(ast::error{ enclosing.error().location }); - } - - auto nextIt = s_rhsops.find(peek_token()->type); - if (nextIt != s_rhsops.end()) { - rhsop_info next = nextIt->second; - - auto expr = std::move(parse_expression_rhs(std::move(rhs), - current.precedence + static_cast(current.associativity == associativity::Right))); - if (expr.has_error()) { - return ast::expression_node_r(ast::error{ expr.error().location }); - } - if (current.type != rhsop_info_t::Unaryop) { - rhs = std::move(expr.value()); - } else { - lhs = std::move(expr.value()); - } - } - - switch (current.type) { - case rhsop_info_t::Unaryop: - lhs = m_arena->allocate_shared(opToken->location, - current.unary, - std::move(lhs)); - break; - case rhsop_info_t::Binop: - 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(opToken->location, - current.assignment, - std::move(lhs), - std::move(rhs)); - break; - case rhsop_info_t::FuncCall: - lhs = m_arena->allocate_shared(opToken->location, - std::move(lhs), - std::move(params)); - break; - } - } - return lhs; -} - -ast::body_r parser::parse_body() { - ast::body body; - - auto begin = eat_token(token_t::LBrace); - if (begin.has_error()) return ast::body_r(ast::error{ begin.error().location }); - body.begin = begin->location; - - while (!peek_token().has_error() && peek_token()->type != token_t::None && peek_token()->type != token_t::RBrace) { - body.statements.push_back(parse_statement()); - } - - auto end = eat_token(token_t::RBrace); - if (end.has_error()) return ast::body_r(ast::error{ end.error().location }); - body.end = end->location; - - return body; -} - -token_r parser::next_token() { - if (!m_peekBuffer.empty()) { - auto token = std::move(m_peekBuffer.back()); - m_peekBuffer.pop_back(); - return token; - } - return m_lexer.next_token(); -} - -const token_r& parser::peek_token() { - if (m_peekBuffer.empty()) { - auto token = m_lexer.next_token(); - return m_peekBuffer.emplace_back(std::move(token)); - } - return m_peekBuffer.front(); -} - -token_r parser::eat_token(token_t 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 next_token(); -} - -} // namespace furc::front diff --git a/furc/src/front/post_process.cpp b/furc/src/front/post_process.cpp deleted file mode 100644 index e43e735..0000000 --- a/furc/src/front/post_process.cpp +++ /dev/null @@ -1,605 +0,0 @@ -#include "furc/front/post_process.hpp" - -#include "furlang/ir/function.hpp" -#include "furlang/ir/instruction.hpp" -#include "furlang/ir/operand.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace furc::front { - -using block_idx = furlang::ir::block_index; -using register_t = furlang::ir::register_t; -using register_op = furlang::ir::register_operand; - -static constexpr block_idx INVALID_BLOCK = std::numeric_limits::max(); - -struct block_info { - std::size_t rpoIndex{ 0 }; - - std::vector predecessors; - std::vector successors; - - block_idx idom = INVALID_BLOCK; - std::vector doms; - std::unordered_set domFrontiers; -}; - -struct register_info { - std::unordered_set defSites; - std::stack renameStack; - std::uint32_t nextVersion{ 0 }; -}; - -struct function_context { - explicit function_context(furlang::ir::function* function) - : function(function) { - build_cfg(); - compute_rpo(); - } - - void build_cfg() { - for (block_idx idx = 0; idx < function->blocks().size(); ++idx) { - const auto& block = function->blocks()[idx]; - - for (const auto& instr : block->instructions()) { - for (const auto& operand : instr->sources()) { - if (operand->type() != furlang::ir::operand_t::Register) continue; - auto reg = operand->reg(); - if (registers[reg].defSites.find(idx) != registers[reg].defSites.end()) continue; - globalRegisters.insert(reg); - } - } - - for (const auto& instr : block->instructions()) { - if (!instr->has_destination() || instr->destination().type() != furlang::ir::operand_t::Register) - continue; - auto reg = instr->destination().reg(); - registers[reg].defSites.insert(idx); - } - - for (const auto& operand : block->exit()->sources()) { - if (operand->type() != furlang::ir::operand_t::Register) continue; - auto reg = operand->reg(); - if (registers[reg].defSites.find(idx) != registers[reg].defSites.end()) continue; - globalRegisters.insert(reg); - } - - const auto& exit = block->exit(); - switch (exit->type()) { - case furlang::ir::instruction_t::Branch: { - const auto& br = dynamic_cast(*exit); - blocks[br.block()].predecessors.push_back(idx); - blocks[idx].successors.push_back(br.block()); - } break; - case furlang::ir::instruction_t::BranchCond: { - const auto& br = dynamic_cast(*exit); - blocks[br.if_block()].predecessors.push_back(idx); - blocks[br.else_block()].predecessors.push_back(idx); - blocks[idx].successors.push_back(br.if_block()); - blocks[idx].successors.push_back(br.else_block()); - } break; - default: break; - } - } - } - - void compute_rpo() { - std::unordered_set visited; - - auto dfs = [&](auto& self, block_idx block) -> void { - visited.insert(block); - for (auto succ : blocks[block].successors) { - if (visited.find(succ) != visited.end()) continue; - self(self, succ); - } - rpoOrder.push_back(block); - }; - - if (!function->blocks().empty()) dfs(dfs, 0); - - std::reverse(rpoOrder.begin(), rpoOrder.end()); - for (std::size_t i = 0; i < rpoOrder.size(); ++i) { - blocks[rpoOrder[i]].rpoIndex = i; - } - } - - void compute_dominance() { - if (rpoOrder.empty()) return; - - const block_idx entry = rpoOrder.front(); - blocks[entry].idom = entry; - - bool changed = true; - while (changed) { - changed = false; - - for (block_idx idx : rpoOrder) { - if (idx == entry) continue; - - block_idx newIdom = INVALID_BLOCK; - bool found = false; - for (auto pred : blocks[idx].predecessors) { - if (blocks[pred].idom == INVALID_BLOCK) continue; - if (found) { - newIdom = intersect(pred, newIdom); - } else { - newIdom = pred; - found = true; - } - } - - if (blocks[idx].idom != newIdom) { - blocks[idx].idom = newIdom; - changed = true; - } - } - } - - for (auto idx : rpoOrder) { - if (idx == entry) continue; - const block_idx parent = blocks[idx].idom; - if (parent != INVALID_BLOCK) blocks[parent].doms.push_back(idx); - } - - for (auto idx : rpoOrder) { - if (blocks[idx].predecessors.size() < 2) continue; - for (auto cur : blocks[idx].predecessors) { - while (cur != blocks[idx].idom) { - blocks[cur].domFrontiers.insert(idx); - cur = blocks[cur].idom; - } - } - } - } - - furlang::ir::function* function; - std::vector rpoOrder; - std::unordered_map blocks; - std::unordered_map registers; - std::unordered_set globalRegisters; -private: - block_idx intersect(block_idx block1, block_idx block2) { - while (block1 != block2) { - while (blocks[block1].rpoIndex > blocks[block2].rpoIndex) - block1 = blocks[block1].idom; - while (blocks[block2].rpoIndex > blocks[block1].rpoIndex) - block2 = blocks[block2].idom; - } - return block1; - } -}; - -static void ssa_stage_rename_block(function_context& ctx, - block_idx idx, - std::unordered_map& regVers, - std::unordered_map>& regVerStacks) { - std::unordered_map pushed; - - const auto& block = ctx.function->blocks()[idx]; - auto it = block->instructions().begin(); - for (; it != block->instructions().end(); ++it) { - auto& instr = *it; - if (instr->type() != furlang::ir::instruction_t::Phi) break; - - const register_t orig = instr->destination().reg(); - const std::uint32_t newVer = regVers[orig]++; - - instr->destination().reg().ver = newVer; - regVerStacks[orig].push(newVer); - ++pushed[orig]; - } - - for (; it != block->instructions().end(); ++it) { - auto& instr = *it; - for (auto& operand : instr->sources()) { - if (operand->type() != furlang::ir::operand_t::Register) continue; - - const register_t orig = operand->reg(); - if (regVerStacks[orig].empty()) continue; - operand->reg().ver = regVerStacks[orig].top(); - } - - if (instr->has_destination() && instr->destination().type() == furlang::ir::operand_t::Register) { - const register_t orig = instr->destination().reg(); - const std::uint32_t newVer = regVers[orig]++; - - instr->destination().reg().ver = newVer; - regVerStacks[orig].push(newVer); - ++pushed[orig]; - } - } - - for (auto& operand : block->exit()->sources()) { - if (operand->type() != furlang::ir::operand_t::Register) continue; - - const auto orig = operand->reg(); - if (regVerStacks[orig].empty()) continue; - operand->reg().ver = regVerStacks[orig].top(); - } - - for (auto succIdx : ctx.blocks[idx].successors) { - const auto& succ = ctx.function->blocks()[succIdx]; - for (auto& instr : succ->instructions()) { - if (instr->type() != furlang::ir::instruction_t::Phi) break; - - auto& phi = dynamic_cast(*instr); - for (auto& pair : phi.labels()) { - if (pair.second != idx) continue; - - auto orig = pair.first.reg(); - if (auto it = regVerStacks.find(orig); it != regVerStacks.end()) - pair.first.reg().ver = it->second.top(); - } - } - } - - for (const auto& child : ctx.blocks[idx].doms) { - ssa_stage_rename_block(ctx, child, regVers, regVerStacks); - } - - for (const auto& [reg, count] : pushed) { - for (std::size_t i = 0; i < count; ++i) - regVerStacks[reg].pop(); - } -} - -static void ssa_stage(function_context& ctx) { - ctx.compute_dominance(); - - std::vector worklist; - for (const auto& [reg, info] : ctx.registers) { - if (info.defSites.size() < 2 || ctx.globalRegisters.find(reg) == ctx.globalRegisters.end()) continue; - - worklist.clear(); - worklist.insert(worklist.end(), info.defSites.begin(), info.defSites.end()); - - std::unordered_set added; - while (!worklist.empty()) { - const auto idx = worklist.back(); - worklist.pop_back(); - for (auto frontier : ctx.blocks[idx].domFrontiers) { - if (added.find(frontier) != added.end()) continue; - added.insert(frontier); - - const auto& target = ctx.function->blocks()[frontier]; - const auto& preds = ctx.blocks[frontier].predecessors; - - auto instr = std::make_unique(reg); - for (auto pred : preds) { - instr->labels().emplace_back(furlang::ir::operand::new_reg(reg), pred); - } - target->instructions().emplace(target->instructions().begin(), std::move(instr)); - - if (info.defSites.find(frontier) == info.defSites.end()) worklist.push_back(frontier); - } - } - } - - std::unordered_map regVers; - std::unordered_map> regVerStacks; - ssa_stage_rename_block(ctx, ctx.rpoOrder.front(), regVers, regVerStacks); -} - -static void dessa_stage(function_context& ctx) { - for (block_idx idx = 0; idx < ctx.function->blocks().size(); ++idx) { - const auto& block = ctx.function->blocks()[idx]; - auto& instrs = block->instructions(); - for (auto it = instrs.begin(); it != instrs.end() && (*it)->type() == furlang::ir::instruction_t::Phi; - it = instrs.erase(it)) { - auto& phi = dynamic_cast(**it); - auto dstReg = phi.destination().reg(); - for (auto& [srcOp, label] : phi.labels()) { - ctx.function->blocks()[label]->instructions().push_back( - std::make_unique(furlang::ir::operand::new_reg(srcOp.reg()), - furlang::ir::operand::new_reg(dstReg))); - } - } - } -} - -struct sccp_lattice { - enum lattice_t { // NOLINT - Top, - Constant, - Bottom, - } type = Top; - std::uint64_t constant = 0; - - bool operator==(const sccp_lattice& other) const { - return type == other.type && (type != Constant || constant == other.constant); - } - - bool operator!=(const sccp_lattice& other) const { return !this->operator==(other); } -}; - -sccp_lattice sccp_stage_get_lattice(std::unordered_map& latticeValues, - const furlang::ir::operand& op) { - if (op.type() == furlang::ir::operand_t::Integer) { - sccp_lattice lat; - lat.type = sccp_lattice::Constant; - lat.constant = op.integer(); - return lat; - } - if (op.type() == furlang::ir::operand_t::Register) { - auto reg = op.reg(); - if (auto it = latticeValues.find(reg); it != latticeValues.end()) return it->second; - return { sccp_lattice::Top }; - } - return { sccp_lattice::Bottom }; -}; - -static void sccp_stage(function_context& ctx) { - using lattice = sccp_lattice; - - std::unordered_map latticeValues; - std::unordered_map> edges; - std::unordered_set execBlocks; - std::set> execEdges; - - std::queue> cfgWorklist; - std::queue ssaWorklist; - - std::unordered_map blockMap; - - for (block_idx idx = 0; idx < ctx.function->blocks().size(); ++idx) { - const auto& block = ctx.function->blocks()[idx]; - auto& instrs = block->instructions(); - for (auto it = instrs.begin(); it != instrs.end(); ++it) { - const auto& instr = *it; - blockMap[instr.get()] = idx; - for (const auto& op : instr->sources()) { - if (op->type() != furlang::ir::operand_t::Register) continue; - edges[op->reg()].push_back(instr.get()); - } - } - - blockMap[block->exit().get()] = idx; - for (const auto& op : block->exit()->sources()) { - if (op->type() != furlang::ir::operand_t::Register) continue; - edges[op->reg()].push_back(block->exit().get()); - } - } - - cfgWorklist.push({ 0, 0 }); - while (!cfgWorklist.empty() || !ssaWorklist.empty()) { - if (!cfgWorklist.empty()) { - auto edge = cfgWorklist.front(); - cfgWorklist.pop(); - block_idx from = edge.first; - block_idx to = edge.second; - - if (execEdges.count(edge) != 0) continue; - execEdges.insert(edge); - - bool firstVisit = (execBlocks.find(to) == execBlocks.end()); - execBlocks.insert(to); - - const auto& block = ctx.function->blocks()[to]; - if (firstVisit) { - for (auto& instr : block->instructions()) { - ssaWorklist.push(instr.get()); - } - ssaWorklist.push(block->exit().get()); - } else { - for (auto& instr : block->instructions()) { - if (instr->type() != furlang::ir::instruction_t::Phi) break; - ssaWorklist.push(instr.get()); - } - } - } - - if (!ssaWorklist.empty()) { - auto* instr = ssaWorklist.front(); - ssaWorklist.pop(); - - block_idx blockIdx = blockMap[instr]; - if (execBlocks.find(blockIdx) == execBlocks.end()) continue; - - lattice newLat = { lattice::Top }; - - switch (instr->type()) { - case furlang::ir::instruction_t::Phi: { - auto& phi = dynamic_cast(*instr); - for (const auto& [op, label] : phi.labels()) { - if (execEdges.count({ label, blockIdx }) == 0) continue; - lattice opLat = sccp_stage_get_lattice(latticeValues, op); - if (opLat.type == lattice::Bottom) newLat.type = lattice::Bottom; - if (opLat.type == lattice::Constant) { - if (newLat.type == lattice::Top) { - newLat = opLat; - } else if (newLat.type == lattice::Constant && newLat.constant != opLat.constant) { - newLat.type = lattice::Bottom; - } - } - } - } break; - case furlang::ir::instruction_t::Assign: { - newLat = sccp_stage_get_lattice(latticeValues, *instr->sources().front()); - } break; - case furlang::ir::instruction_t::Add: - case furlang::ir::instruction_t::Sub: - case furlang::ir::instruction_t::Mul: - case furlang::ir::instruction_t::Div: - case furlang::ir::instruction_t::Mod: - case furlang::ir::instruction_t::Eq: - case furlang::ir::instruction_t::NotEq: - case furlang::ir::instruction_t::LessThan: - case furlang::ir::instruction_t::GreaterThan: - case furlang::ir::instruction_t::LessEq: - case furlang::ir::instruction_t::GreaterEq: { - lattice lhs = sccp_stage_get_lattice(latticeValues, *instr->sources()[0]); - lattice rhs = sccp_stage_get_lattice(latticeValues, *instr->sources()[1]); - - if (lhs.type == lattice::Bottom || rhs.type == lattice::Bottom) { - newLat.type = lattice::Bottom; - } else if (lhs.type == lattice::Constant && rhs.type == lattice::Constant) { - newLat.type = lattice::Constant; - switch (instr->type()) { - case furlang::ir::instruction_t::Add: newLat.constant = lhs.constant + rhs.constant; break; - case furlang::ir::instruction_t::Sub: newLat.constant = lhs.constant - rhs.constant; break; - case furlang::ir::instruction_t::Mul: newLat.constant = lhs.constant * rhs.constant; break; - case furlang::ir::instruction_t::Div: newLat.constant = lhs.constant / rhs.constant; break; - case furlang::ir::instruction_t::Mod: newLat.constant = lhs.constant % rhs.constant; break; - case furlang::ir::instruction_t::Eq: - newLat.constant = (lhs.constant == rhs.constant) ? 1 : 0; - break; - case furlang::ir::instruction_t::NotEq: - newLat.constant = (lhs.constant != rhs.constant) ? 1 : 0; - break; - case furlang::ir::instruction_t::LessThan: - newLat.constant = (lhs.constant < rhs.constant) ? 1 : 0; - break; - case furlang::ir::instruction_t::GreaterThan: - newLat.constant = (lhs.constant > rhs.constant) ? 1 : 0; - break; - case furlang::ir::instruction_t::LessEq: - newLat.constant = (lhs.constant <= rhs.constant) ? 1 : 0; - break; - case furlang::ir::instruction_t::GreaterEq: - newLat.constant = (lhs.constant >= rhs.constant) ? 1 : 0; - break; - default: throw std::runtime_error("unreachable"); - } - } - } break; - default: break; - } - - if (instr->has_destination() && instr->destination().type() == furlang::ir::operand_t::Register) { - auto dst = instr->destination().reg(); - if (!(latticeValues[dst] == newLat)) { - latticeValues[dst] = newLat; - for (auto* uInstr : edges[dst]) - ssaWorklist.push(uInstr); - } - } - - if (instr == ctx.function->blocks()[blockIdx]->exit().get()) { - auto* exit = ctx.function->blocks()[blockIdx]->exit().get(); - if (exit->type() == furlang::ir::instruction_t::Branch) { - auto& br = dynamic_cast(*exit); - cfgWorklist.push({ blockIdx, br.block() }); - } else if (exit->type() == furlang::ir::instruction_t::BranchCond) { - auto& br = dynamic_cast(*exit); - lattice cond = sccp_stage_get_lattice(latticeValues, *exit->sources()[0]); - - if (cond.type == lattice::Constant) { - if (cond.constant != 0) - cfgWorklist.push({ blockIdx, br.if_block() }); - else - cfgWorklist.push({ blockIdx, br.else_block() }); - } else { - cfgWorklist.push({ blockIdx, br.if_block() }); - cfgWorklist.push({ blockIdx, br.else_block() }); - } - } - } - } - } - - for (block_idx i = 0; i < ctx.function->blocks().size(); ++i) { - if (execBlocks.find(i) == execBlocks.end()) { - ctx.function->blocks()[i]->instructions().clear(); - continue; - } - - const auto& block = ctx.function->blocks()[i]; - - for (auto& instr : block->instructions()) { - for (auto& op : instr->sources()) { - if (op->type() != furlang::ir::operand_t::Register) continue; - auto reg = op->reg(); - if (latticeValues[reg].type != lattice::Constant) continue; - *op = furlang::ir::operand::new_integer(latticeValues[reg].constant); - } - } - - auto* exit = block->exit().get(); - if (exit->type() != furlang::ir::instruction_t::BranchCond) continue; - auto& br = dynamic_cast(*exit); - lattice cond = sccp_stage_get_lattice(latticeValues, *exit->sources()[0]); - if (cond.type != lattice::Constant) continue; - block_idx target = (cond.constant != 0) ? br.if_block() : br.else_block(); - block->exit() = std::make_unique(target); - } -} - -static void adce_stage(function_context& ctx) { - std::unordered_map defMap; - std::unordered_set alive; - std::queue worklist; - - for (block_idx blockIdx = 0; blockIdx < ctx.function->blocks().size(); ++blockIdx) { - const auto& block = ctx.function->blocks()[blockIdx]; - - for (auto& instr : block->instructions()) { - if (instr->has_destination() && instr->destination().type() == furlang::ir::operand_t::Register) { - defMap[instr->destination().reg()] = instr.get(); - } - if (instr->type() == furlang::ir::instruction_t::Call) { - // TODO: Check if the function has side effects - if (alive.insert(instr.get()).second) worklist.push(instr.get()); - } - } - - auto* exit = block->exit().get(); - alive.insert(exit); - worklist.push(exit); - } - - while (!worklist.empty()) { - const auto* instr = worklist.front(); - worklist.pop(); - - for (const auto& op : instr->sources()) { - if (op->type() != furlang::ir::operand_t::Register) continue; - auto src = op->reg(); - - if (defMap.find(src) == defMap.end()) continue; - auto* defInstr = defMap[src]; - if (alive.insert(defInstr).second) { - worklist.push(defInstr); - } - } - } - - for (block_idx blockIdx = 0; blockIdx < ctx.function->blocks().size(); ++blockIdx) { - const auto& block = ctx.function->blocks()[blockIdx]; - auto& instrs = block->instructions(); - - auto it = instrs.begin(); - while (it != instrs.end()) { - it = (alive.find(it->get()) != alive.end()) ? it + 1 : instrs.erase(it); - } - } -} - -void post_process::process(furlang::ir::mod& mod) { - for (const auto& func : mod.functions()) { - if (!func || func->blocks().empty()) continue; - function_context ctx{ func.get() }; - - for (const auto& stage : m_stages) { - switch (stage) { - case Ssa: ssa_stage(ctx); break; - case Sccp: sccp_stage(ctx); break; - case Adce: adce_stage(ctx); break; - case DeSsa: dessa_stage(ctx); break; - } - } - } -} - -} // namespace furc::front diff --git a/furc/src/main.cpp b/furc/src/main.cpp index 84f97ed..254b47a 100644 --- a/furc/src/main.cpp +++ b/furc/src/main.cpp @@ -1,89 +1,7 @@ -#ifndef LIBFURC - -#include "furc/ast/program.hpp" -#include "furc/back/furvm.hpp" -#include "furc/front/ir_generator.hpp" -#include "furc/front/parser.hpp" -#include "furc/front/post_process.hpp" -#include "furlang/arena.hpp" - -#include -#include #include int main(void) { - try { - std::string programStr = R"( - private native func print(value: int32); + std::cout << "Farewell, stasiu!\n"; - func main() -> int32 { - x = 0; - y = 10; - z = 1; - while (x < y) { - x = x + z; - } - print(sizeof x); - } - )"; - furlang::arena arena{}; - furc::front::parser parser(arena, "", programStr); - furc::front::ir_generator generator; - - auto programResult = parser.parse(); - if (programResult.has_error()) { - std::cerr << programResult.error() << '\n'; - return 1; - } - const auto& program = *programResult; - program->accept(generator); - - auto mod = std::move(generator.move_module()); - - furc::front::post_process postProcess; - postProcess.push_stage(furc::front::post_process::Ssa); - postProcess.push_stage(furc::front::post_process::Sccp); - postProcess.push_stage(furc::front::post_process::Adce); - postProcess.push_stage(furc::front::post_process::DeSsa); - postProcess.process(mod); - - std::cout << "Generated IR:\n"; - for (const auto& function : mod.functions()) { - std::cout << function->name() << ":\n"; - furlang::ir::block_index blockIndex = 0; - for (const auto& block : function->blocks()) { - std::cout << " # block " << blockIndex++ << '\n'; - for (const auto& instruction : block->instructions()) { - std::cout << " " << *instruction << '\n'; - } - std::cout << " " << *block->exit() << '\n'; - } - } - - auto context = std::make_shared(); - auto furvmMod = context->emplace("main", furc::back::furvm_generator::generate(mod)); - - std::ofstream file("./a.fmod", std::ios::binary); - furvmMod->serialize(file); - file.close(); - - furvmMod->set_native_function("print", - [](furvm::executor& executor) { std::cout << executor.load_thing(0)->integer() << '\n'; }); - - furvm::executor_h executor = context->emplace_executor(context); - executor->push_frame(furvmMod, *furvmMod->function_at("main", furvm::function_sig{})); - - std::cout << "--- Interpreting:\n"; - - while ((executor->flags() & furvm::executor_flags::Done) != furvm::executor_flags::Done) { - executor->step(); - } - - return 0; - } catch (...) { - std::cerr << "Caught an exception in main!\n"; - return 1; - } + return 0; } - -#endif // LIBFURC diff --git a/furc/test/lexer.cpp b/furc/test/lexer.cpp index 17b7c70..29838b3 100644 --- a/furc/test/lexer.cpp +++ b/furc/test/lexer.cpp @@ -1,78 +1,7 @@ // NOLINTBEGIN(readability-identifier-naming) -#include "furc/front/lexer.hpp" - #include "gtest/gtest.h" -#include -namespace { +namespace {} // namespace -using namespace furc::front; -using namespace std::string_view_literals; -using namespace std::string_literals; - -using lexer_case = std::pair>; - -class LexerTestingFixture : public testing::TestWithParam {}; - -TEST_P(LexerTestingFixture, LexerTest) { - auto [code, expected] = GetParam(); - - lexer lexer("", code); - auto it = expected.begin(); - while (it != expected.end()) { - const auto& expected = *it++; - - EXPECT_EQ(lexer.next_token(), expected); - } - - auto eof = std::move(lexer.next_token()); - ASSERT_TRUE(eof.has_error()); - ASSERT_EQ(eof.error().type, token_error_t::EndOfFile); -} - -furc::location loc(size_t col, size_t line) { - return furc::location{ "", line, col }; -} - -INSTANTIATE_TEST_SUITE_P(EmptyTests, - LexerTestingFixture, - testing::Values(lexer_case("", {}), lexer_case(" ", {}), lexer_case("\t", {}), lexer_case("\n", {}))); - -INSTANTIATE_TEST_SUITE_P(Comments, - LexerTestingFixture, - testing::Values(lexer_case("(/** skibidi **/func{//)\n}", - { { loc(0, 0), token_t::LParen }, - { loc(16, 0), keyword_token::Func }, - { loc(20, 0), token_t::LBrace }, - { loc(0, 1), token_t::RBrace } }))); - -INSTANTIATE_TEST_SUITE_P(Integers, - LexerTestingFixture, - testing::Values(lexer_case("67 6\n7", { { loc(0, 0), 67 }, { loc(3, 0), 6 }, { loc(0, 1), 7 } }), - lexer_case("18446744073709551615\n18446744073709551616", - { { loc(0, 0), 18446744073709551615ULL }, - token_r( - token_error{ loc(0, 1), token_error_t::IntegerOverflow, std::string("18446744073709551616") }) }))); - -INSTANTIATE_TEST_SUITE_P(Tokens, - LexerTestingFixture, - testing::Values(lexer_case("()\n\t\t{\n}[\"shto-to\"]; :,.main return func", - { { loc(0, 0), token_t::LParen }, - { loc(1, 0), token_t::RParen }, - { loc(2, 1), token_t::LBrace }, - { loc(0, 2), token_t::RBrace }, - { loc(1, 2), token_t::LBracket }, - { loc(2, 2), token_t::String, "shto-to"sv }, - { loc(10, 2), token_t::RBracket }, - { loc(11, 2), token_t::Semicolon }, - { loc(15, 2), token_t::Colon }, - { loc(16, 2), token_t::Comma }, - { loc(17, 2), token_t::Dot }, - { loc(18, 2), token_t::Identifier, "main"sv }, - { loc(23, 2), keyword_token::Return }, - { loc(30, 2), keyword_token::Func } }))); - -} // namespace - -// NOLINTEND(readability-identifier-naming) \ No newline at end of file +// NOLINTEND(readability-identifier-naming) diff --git a/furc/test/parser.cpp b/furc/test/parser.cpp deleted file mode 100644 index 4c6d888..0000000 --- a/furc/test/parser.cpp +++ /dev/null @@ -1,274 +0,0 @@ -#include "furc/front/parser.hpp" - -#include "furc/ast/declaration.hpp" // IWYU pragma: keep -#include "furc/ast/expression.hpp" // IWYU pragma: keep -#include "furc/ast/literal.hpp" // IWYU pragma: keep -#include "furc/ast/program.hpp" // IWYU pragma: keep -#include "furc/ast/statement.hpp" // IWYU pragma: keep - -#include "gtest/gtest.h" // IWYU pragma: keep - -namespace { - -using namespace furc::front; -using namespace furc::ast; -using namespace std::string_view_literals; - -// TEST(Parser, EmptyFunctions) { -// parser parser("", "func main() {}\nfunc foo();"); -// auto program = parser.parse(); -// EXPECT_TRUE(program.present()); -// EXPECT_EQ(program->declarations().size(), 2); -// { -// auto first = program->declarations()[0]; -// EXPECT_TRUE(first.present()); -// EXPECT_EQ(first->declaration_type(), declaration_node_t::FuncDef); -// function_definition_node_h funcDef = first; -// EXPECT_EQ(funcDef->name()->string, "main"); -// EXPECT_EQ(funcDef->body()->statements.size(), 0); -// } -// { -// auto second = program->declarations()[1]; -// EXPECT_TRUE(second.present()); -// EXPECT_EQ(second->declaration_type(), declaration_node_t::Func); -// function_declaration_node_h funcDecl = second; -// EXPECT_EQ(funcDecl->name()->string, "foo"); -// } -// } - -// #define EXPECT_INTLIT(expr, integer) \ -// do { \ -// EXPECT_EQ((expr)->expression_type(), expression_node_t::Literal); \ -// literal_node_h literal = (expr); \ -// EXPECT_EQ(literal->literal_type(), literal_node_t::Integer); \ -// integer_literal_node_h intLit = literal; \ -// EXPECT_EQ(intLit->value(), integer_token((integer))); \ -// } while (0) - -// TEST(Parser, Literals) { -// parser parser("", R"( -// func test1() { return 67; } -// func test2() { return "uwu"; } -// )"); -// auto program = parser.parse(); -// EXPECT_TRUE(program.present()); -// EXPECT_EQ(program->declarations().size(), 2); -// { -// auto test1 = program->declarations()[0]; -// EXPECT_TRUE(test1.present()); -// EXPECT_EQ(test1->declaration_type(), declaration_node_t::FuncDef); -// function_definition_node_h funcDef = test1; -// EXPECT_EQ(funcDef->name()->string, "test1"); -// EXPECT_EQ(funcDef->body()->statements.size(), 1); -// return_statement_node_h ret = funcDef->body()->statements[0]; -// EXPECT_INTLIT(ret->value(), 67); -// } -// { -// auto test2 = program->declarations()[1]; -// EXPECT_TRUE(test2.present()); -// EXPECT_EQ(test2->declaration_type(), declaration_node_t::FuncDef); -// function_definition_node_h funcDecl = test2; -// EXPECT_EQ(funcDecl->name()->string, "test2"); -// } -// } - -// #define EXPECT_VARREAD(expr, varname) \ -// do { \ -// EXPECT_EQ((expr)->expression_type(), expression_node_t::VarRead); \ -// var_read_expression_node_h varRead = (expr); \ -// EXPECT_EQ(varRead->get_name(), (varname)); \ -// } while (0) - -// // TODO: Use arena (I am too exhausted rn to do it) -// TEST(Parser, OperatorPrecedence_AddMul) { -// parser parser("", "func main() { return 1 + 2 * 3; }"); -// auto program = parser.parse(); -// EXPECT_TRUE(program.present()); -// EXPECT_EQ(program->declarations().size(), 1); -// auto func = program->declarations()[0]; -// EXPECT_TRUE(func.present()); -// EXPECT_EQ(func->declaration_type(), declaration_node_t::FuncDef); -// function_definition_node_h funcDef = func; -// EXPECT_EQ(funcDef->name()->string, "main"); -// EXPECT_EQ(funcDef->body()->statements.size(), 1); -// return_statement_node_h ret = funcDef->body()->statements[0]; - -// auto retVal = ret->value(); -// EXPECT_TRUE(retVal.present()); - -// EXPECT_EQ(retVal->expression_type(), expression_node_t::Binop); -// binop_expression_node_h add = retVal; -// EXPECT_EQ(add->type(), binop_expression_node_t::Add); -// EXPECT_INTLIT(add->lhs(), 1); - -// EXPECT_EQ(add->rhs()->expression_type(), expression_node_t::Binop); -// binop_expression_node_h mul = add->rhs(); -// EXPECT_EQ(mul->type(), binop_expression_node_t::Mul); -// EXPECT_INTLIT(mul->lhs(), 2); -// EXPECT_INTLIT(mul->rhs(), 3); -// } - -// TEST(Parser, OperatorPrecedence_Complex) { -// parser parser("", "func main() { return 1 + 2 * 3 - 4 / 2; }"); -// auto program = parser.parse(); -// EXPECT_TRUE(program.present()); -// EXPECT_EQ(program->declarations().size(), 1); -// auto func = program->declarations()[0]; -// EXPECT_TRUE(func.present()); -// EXPECT_EQ(func->declaration_type(), declaration_node_t::FuncDef); -// function_definition_node_h funcDef = func; -// EXPECT_EQ(funcDef->name()->string, "main"); -// EXPECT_EQ(funcDef->body()->statements.size(), 1); -// return_statement_node_h ret = funcDef->body()->statements[0]; - -// auto retVal = ret->value(); -// EXPECT_TRUE(retVal.present()); - -// EXPECT_EQ(retVal->expression_type(), expression_node_t::Binop); -// binop_expression_node_h sub = retVal; -// EXPECT_EQ(sub->type(), binop_expression_node_t::Sub); - -// EXPECT_EQ(sub->lhs()->expression_type(), expression_node_t::Binop); -// binop_expression_node_h add = sub->lhs(); -// EXPECT_EQ(add->type(), binop_expression_node_t::Add); -// EXPECT_INTLIT(add->lhs(), 1); - -// EXPECT_EQ(add->rhs()->expression_type(), expression_node_t::Binop); -// binop_expression_node_h mul = add->rhs(); -// EXPECT_EQ(mul->type(), binop_expression_node_t::Mul); -// EXPECT_INTLIT(mul->lhs(), 2); -// EXPECT_INTLIT(mul->rhs(), 3); - -// EXPECT_EQ(sub->rhs()->expression_type(), expression_node_t::Binop); -// binop_expression_node_h div = sub->rhs(); -// EXPECT_EQ(div->type(), binop_expression_node_t::Div); -// EXPECT_INTLIT(div->lhs(), 4); -// EXPECT_INTLIT(div->rhs(), 2); -// } - -// TEST(Parser, UnaryOperator_Simple) { -// parser parser("", "func main() { return -5; }"); -// auto program = parser.parse(); -// EXPECT_TRUE(program.present()); -// EXPECT_EQ(program->declarations().size(), 1); -// auto func = program->declarations()[0]; -// EXPECT_TRUE(func.present()); -// EXPECT_EQ(func->declaration_type(), declaration_node_t::FuncDef); -// function_definition_node_h funcDef = func; -// EXPECT_EQ(funcDef->name()->string, "main"); -// EXPECT_EQ(funcDef->body()->statements.size(), 1); -// return_statement_node_h ret = funcDef->body()->statements[0]; - -// auto retVal = ret->value(); -// EXPECT_TRUE(retVal.present()); - -// EXPECT_EQ(retVal->expression_type(), expression_node_t::Unaryop); -// unaryop_expression_node_h neg = retVal; -// EXPECT_EQ(neg->type(), unaryop_expression_node_t::Negative); -// EXPECT_INTLIT(neg->get_node(), 5); -// } - -// TEST(Parser, UnaryOperator_PrePost) { -// parser parser("", "func main() { return --5++; }"); -// auto program = parser.parse(); -// EXPECT_TRUE(program.present()); -// EXPECT_EQ(program->declarations().size(), 1); -// auto func = program->declarations()[0]; -// EXPECT_TRUE(func.present()); -// EXPECT_EQ(func->declaration_type(), declaration_node_t::FuncDef); -// function_definition_node_h funcDef = func; -// EXPECT_EQ(funcDef->name()->string, "main"); -// EXPECT_EQ(funcDef->body()->statements.size(), 1); -// return_statement_node_h ret = funcDef->body()->statements[0]; - -// auto retVal = ret->value(); -// EXPECT_TRUE(retVal.present()); - -// EXPECT_EQ(retVal->expression_type(), expression_node_t::Unaryop); -// unaryop_expression_node_h inc = retVal; -// EXPECT_EQ(inc->type(), unaryop_expression_node_t::PostfixIncrement); - -// EXPECT_EQ(inc->get_node()->expression_type(), expression_node_t::Unaryop); -// unaryop_expression_node_h dec = inc->get_node(); -// EXPECT_INTLIT(dec->get_node(), 5); -// } - -// TEST(Parser, Paren) { -// parser parser("", "func main() { return --(x++); }"); -// auto program = parser.parse(); -// EXPECT_TRUE(program.present()); -// EXPECT_EQ(program->declarations().size(), 1); -// auto func = program->declarations()[0]; -// EXPECT_TRUE(func.present()); -// EXPECT_EQ(func->declaration_type(), declaration_node_t::FuncDef); -// function_definition_node_h funcDef = func; -// EXPECT_EQ(funcDef->name()->string, "main"); -// EXPECT_EQ(funcDef->body()->statements.size(), 1); -// return_statement_node_h ret = funcDef->body()->statements[0]; - -// auto retVal = ret->value(); -// EXPECT_TRUE(retVal.present()); - -// EXPECT_EQ(retVal->expression_type(), expression_node_t::Unaryop); -// unaryop_expression_node_h dec = retVal; -// EXPECT_EQ(dec->type(), unaryop_expression_node_t::PrefixDecrement); - -// EXPECT_EQ(dec->get_node()->expression_type(), expression_node_t::Unaryop); -// unaryop_expression_node_h inc = dec->get_node(); -// EXPECT_EQ(inc->type(), unaryop_expression_node_t::PostfixIncrement); -// EXPECT_VARREAD(inc->get_node(), "x"sv); -// } - -// TEST(Parser, Assignment) { -// parser parser("", "func main() { x = 10; }"); -// auto program = parser.parse(); -// EXPECT_TRUE(program.present()); -// EXPECT_EQ(program->declarations().size(), 1); -// auto func = program->declarations()[0]; -// EXPECT_TRUE(func.present()); -// EXPECT_EQ(func->declaration_type(), declaration_node_t::FuncDef); -// function_definition_node_h funcDef = func; -// EXPECT_EQ(funcDef->name()->string, "main"); -// EXPECT_EQ(funcDef->body()->statements.size(), 1); - -// EXPECT_EQ(funcDef->body()->statements[0]->statement_type(), statement_node_t::Expression); -// expression_node_h expr = funcDef->body()->statements[0]; - -// EXPECT_EQ(expr->expression_type(), expression_node_t::VarAssign); -// var_assign_expression_node_h assign = expr; -// EXPECT_EQ(assign->compound(), binop_expression_node_t::None); - -// EXPECT_VARREAD(assign->lhs(), "x"sv); - -// expression_node_h rhs = assign->rhs(); -// EXPECT_EQ(rhs->expression_type(), expression_node_t::Literal); -// EXPECT_INTLIT(rhs, 10); -// } - -// TEST(Parser, CompoundAssignment) { -// parser parser("", "func main() { x += 10; }"); -// auto program = parser.parse(); -// EXPECT_TRUE(program.present()); -// EXPECT_EQ(program->declarations().size(), 1); -// auto func = program->declarations()[0]; -// EXPECT_TRUE(func.present()); -// EXPECT_EQ(func->declaration_type(), declaration_node_t::FuncDef); -// function_definition_node_h funcDef = func; -// EXPECT_EQ(funcDef->name()->string, "main"); -// EXPECT_EQ(funcDef->body()->statements.size(), 1); - -// EXPECT_EQ(funcDef->body()->statements[0]->statement_type(), statement_node_t::Expression); -// expression_node_h expr = funcDef->body()->statements[0]; - -// EXPECT_EQ(expr->expression_type(), expression_node_t::VarAssign); -// var_assign_expression_node_h assign = expr; -// EXPECT_EQ(assign->compound(), binop_expression_node_t::Add); - -// EXPECT_VARREAD(assign->lhs(), "x"sv); - -// expression_node_h rhs = assign->rhs(); -// EXPECT_EQ(rhs->expression_type(), expression_node_t::Literal); -// EXPECT_INTLIT(rhs, 10); -// } - -} // namespace \ No newline at end of file diff --git a/furlang/include/furlang/ir/instruction.hpp b/furlang/include/furlang/ir/instruction.hpp index 4c298ab..61bb81f 100644 --- a/furlang/include/furlang/ir/instruction.hpp +++ b/furlang/include/furlang/ir/instruction.hpp @@ -3,6 +3,7 @@ #include "furlang/ir/operand.hpp" +#include #include #include #include @@ -63,6 +64,7 @@ static inline std::ostream& operator<<(std::ostream& os, instruction_t type) { case instruction_t::Return: return os << "return"; case instruction_t::Phi: return os << "phi"; } + throw std::runtime_error("unreachable"); } /** @@ -272,9 +274,7 @@ private: operand m_source; operand m_destination; protected: - std::ostream& print(std::ostream& os) const override { - return os << "assign " << m_source << ", " << m_destination; - } + std::ostream& print(std::ostream& os) const override { return os << m_destination << " = " << m_source; } }; /** @@ -751,14 +751,13 @@ private: std::vector m_args; protected: std::ostream& print(std::ostream& os) const override { - os << "call " << m_name << '('; + os << m_dst << " = " << m_name << '('; bool first = true; - for (const auto& op : m_args) { + for (std::size_t i = 0; i < m_args.size(); ++i) { if (!first) os << ", "; first = false; - os << op; } - return os << ") = " << m_dst; + return os << ')'; } }; diff --git a/furvm/include/furvm/context.hpp b/furvm/include/furvm/context.hpp index ef022a9..96455d5 100644 --- a/furvm/include/furvm/context.hpp +++ b/furvm/include/furvm/context.hpp @@ -126,7 +126,7 @@ public: */ thing_allocator thing_alloc() const { return m_thingAllocator; } - thing_type_store& thing_type_store() { return m_thingTypeStore; } + thing_type_store& tt_store() { return m_thingTypeStore; } private: handle_container m_modules; handle_container m_things; diff --git a/furvm/include/furvm/executor.hpp b/furvm/include/furvm/executor.hpp index 5f82db3..4a11511 100644 --- a/furvm/include/furvm/executor.hpp +++ b/furvm/include/furvm/executor.hpp @@ -169,7 +169,7 @@ public: private: thing_type thing_type_impl(mod_h mod, mod_type type) const; - thing_type* thing_type(const mod_h& mod, const mod_type& type) const; + thing_type* mod_to_thing_type(const mod_h& mod, const mod_type& type) const; private: executor_flags m_flags{}; // NOLINT(bugprone-invalid-enum-default-initialization) context_p m_context; diff --git a/furvm/include/furvm/module.hpp b/furvm/include/furvm/module.hpp index 8f1045c..cc46d45 100644 --- a/furvm/include/furvm/module.hpp +++ b/furvm/include/furvm/module.hpp @@ -18,12 +18,12 @@ namespace furvm { struct mod_type { - struct array { + struct array_value { mod_type_id typeId; std::size_t size; }; - struct imprt { + struct import_value { mod_id modId; mod_type_id typeId; }; @@ -47,8 +47,8 @@ struct mod_type { union value { std::nullptr_t null = nullptr; mod_type_id typeRef; - array array; - imprt imprt; + array_value array; + import_value imprt; value() = default; @@ -91,8 +91,8 @@ struct mod_type { ~mod_type() { switch (type) { - case Array: value.array.~array(); break; - case Import: value.imprt.~imprt(); break; + case Array: value.array.~array_value(); break; + case Import: value.imprt.~import_value(); break; default: break; } } @@ -100,8 +100,8 @@ struct mod_type { mod_type(mod_type&& other) noexcept : type(other.type) { switch (type) { - case Array: new (&value.array) array(other.value.array); break; - case Import: new (&value.imprt) imprt(std::move(other.value.imprt)); break; + case Array: new (&value.array) array_value(other.value.array); break; + case Import: new (&value.imprt) import_value(std::move(other.value.imprt)); break; default: break; } other.type = Count; @@ -111,8 +111,8 @@ struct mod_type { if (this == &other) return *this; type = other.type; switch (type) { - case Array: new (&value.array) array(other.value.array); break; - case Import: new (&value.imprt) imprt(std::move(other.value.imprt)); break; + case Array: new (&value.array) array_value(other.value.array); break; + case Import: new (&value.imprt) import_value(std::move(other.value.imprt)); break; default: break; } other.type = Count; @@ -122,8 +122,8 @@ struct mod_type { mod_type(const mod_type& other) : type(other.type) { switch (type) { - case Array: new (&value.array) array(other.value.array); break; - case Import: new (&value.imprt) imprt(other.value.imprt); break; + case Array: new (&value.array) array_value(other.value.array); break; + case Import: new (&value.imprt) import_value(other.value.imprt); break; default: break; } } @@ -132,8 +132,8 @@ struct mod_type { if (this == &other) return *this; type = other.type; switch (type) { - case Array: new (&value.array) array(other.value.array); break; - case Import: new (&value.imprt) imprt(other.value.imprt); break; + case Array: new (&value.array) array_value(other.value.array); break; + case Import: new (&value.imprt) import_value(other.value.imprt); break; default: break; } return *this; @@ -181,7 +181,7 @@ public: * @param offset An offset of the byte. * @return The byte. */ - constexpr byte byte(std::size_t offset) const { return m_bytecode.at(offset); } + byte byte_at(std::size_t offset) const { return m_bytecode.at(offset); } /** * @brief Returns the module's bytecode. diff --git a/furvm/include/furvm/thing.hpp b/furvm/include/furvm/thing.hpp index 153ac1d..ec87dd2 100644 --- a/furvm/include/furvm/thing.hpp +++ b/furvm/include/furvm/thing.hpp @@ -30,7 +30,7 @@ struct thing_type { using u32 = std::uint32_t; using u64 = std::uint64_t; - struct array { + struct array_value { thing_type* type; std::size_t size; }; @@ -53,7 +53,7 @@ struct thing_type { union value { std::nullptr_t null = nullptr; thing_type* typeRef; - array array; + array_value array; value() = default; @@ -197,12 +197,9 @@ class thing final { public: using allocator_type = Allocator; /**< Allocator type. */ public: - union array { - std::byte flat[]; - struct { - std::size_t size; - std::byte* data; - } dynamic; + struct dynamic_array { + std::size_t size; + std::byte* data; }; public: /** @@ -270,7 +267,7 @@ public: case thing_type::U32: case thing_type::U64: case thing_type::Ptr: std::memcpy(res.m_data, m_data, m_size); return std::move(res); - case thing_type::Array: copy_list(m_type, res.get(), get()); return std::move(res); + case thing_type::Array: copy_list(m_type, res.m_data, m_data); return std::move(res); case thing_type::Ref: throw std::runtime_error("cannot clone references"); case thing_type::Count: break; } @@ -450,16 +447,14 @@ public: if (!is(thing_type::Array)) throw bad_thing_access(); if (true_type().value.array.size > 0) throw std::runtime_error("cannot resize a static array"); - auto& array = get(); - if (newSize < 0 || newSize == array.dynamic.size) return; + auto& array = get(); + if (newSize < 0 || newSize == array.size) return; std::size_t innerSize = compute_size_na(*true_type().value.array.type); std::byte* newData = new std::byte[innerSize * newSize]; - std::memcpy(newData, - array.dynamic.data, - innerSize * std::min(static_cast(array.dynamic.size), newSize)); - array.dynamic.size = newSize; - delete[] array.dynamic.data; - array.dynamic.data = newData; + std::memcpy(newData, array.data, innerSize * std::min(static_cast(array.size), newSize)); + array.size = newSize; + delete[] array.data; + array.data = newData; } thing at(thing_type::u64 index) const { @@ -467,23 +462,22 @@ public: std::size_t elementSize = compute_size_na(*m_type.value.array.type); if (m_type.value.array.size == 0) { - auto& array = get(); - if (index < 0 || index >= array.dynamic.size) throw std::out_of_range("index out of range"); + auto& array = get(); + if (index < 0 || index >= array.size) throw std::out_of_range("index out of range"); thing ref = { { thing_type::Ref, m_type.value.array.type }, m_allocator }; - ref.m_data = array.dynamic.data + (index * elementSize); + ref.m_data = array.data + (index * elementSize); return ref; } - std::byte* data = reinterpret_cast(m_data)->flat; if (index < 0 || index >= m_type.value.array.size) throw std::out_of_range("index out of range"); thing ref = { { thing_type::Ref, m_type.value.array.type }, m_allocator }; - ref.m_data = data + (index * elementSize); + ref.m_data = m_data + (index * elementSize); return ref; } thing_type::u64 length() const { if (!is(thing_type::Array)) throw bad_thing_access(); - return true_type().value.array.size == 0 ? get().dynamic.size : true_type().value.array.size; + return true_type().value.array.size == 0 ? get().size : true_type().value.array.size; } template >> @@ -529,29 +523,28 @@ public: throw std::runtime_error("unreachable"); } private: - static void copy_list(const thing_type& arrayType, array& dst, const array& src) { + static void copy_list(const thing_type& arrayType, void* dst, const void* src) { if (arrayType.type != thing_type::Array || arrayType.value.array.type == nullptr) throw std::runtime_error("invalid type"); const auto& innerType = *arrayType.value.array.type; std::size_t elementSize = compute_size_na(innerType); - std::byte* data = nullptr; - const std::byte* srcData = nullptr; - std::size_t size = 0; + std::size_t size = 0; if (arrayType.value.array.size == 0) { - size = dst.dynamic.size = src.dynamic.size; - if (dst.dynamic.size < 0) { - dst.dynamic.data = nullptr; + const dynamic_array& srcDynArr = *std::launder(reinterpret_cast(src)); + dynamic_array& dstDynArr = *std::launder(reinterpret_cast(dst)); + + size = dstDynArr.size = srcDynArr.size; + if (dstDynArr.size < 0) { + dstDynArr.data = nullptr; return; } - srcData = src.dynamic.data; - data = dst.dynamic.data = new std::byte[dst.dynamic.size]; + src = srcDynArr.data; + dst = dstDynArr.data = new std::byte[dstDynArr.size]; } else { - data = dst.flat; - srcData = src.flat; - size = arrayType.value.array.size; + size = arrayType.value.array.size; } switch (innerType.type) { @@ -564,12 +557,12 @@ private: case thing_type::U32: case thing_type::U64: case thing_type::Ptr: - case thing_type::Ref: std::memcpy(dst.flat, src.flat, size); return; + case thing_type::Ref: std::memcpy(dst, src, size * elementSize); return; case thing_type::Array: for (std::size_t i = 0; i < size; ++i) { copy_list(*innerType.value.array.type, - *std::launder(reinterpret_cast(data + (i * elementSize))), - *std::launder(reinterpret_cast(srcData + (i * elementSize)))); + reinterpret_cast(dst) + (i * elementSize), + reinterpret_cast(src) + (i * elementSize)); } return; case thing_type::Count: break; @@ -590,7 +583,7 @@ private: case thing_type::Ptr: return sizeof(void*); case thing_type::Ref: return compute_size_na(*type.value.typeRef); case thing_type::Array: - return type.value.array.size == 0 ? sizeof(array) + return type.value.array.size == 0 ? sizeof(dynamic_array) : compute_size_na(*type.value.array.type) * type.value.array.size; case thing_type::Count: break; } diff --git a/furvm/src/executor.cpp b/furvm/src/executor.cpp index d74918c..56e6a79 100644 --- a/furvm/src/executor.cpp +++ b/furvm/src/executor.cpp @@ -30,18 +30,18 @@ thing_type executor::thing_type_impl(mod_h mod, mod_type type) const { case thing_type::U16: case thing_type::U32: case thing_type::U64: return { static_cast(type.type) }; - case thing_type::Ptr: return { thing_type::Ptr, thing_type(mod, *mod->type_at(type.value.typeRef)) }; + case thing_type::Ptr: return { thing_type::Ptr, mod_to_thing_type(mod, *mod->type_at(type.value.typeRef)) }; case thing_type::Array: { return { static_cast(type.type), - { thing_type(mod, *mod->type_at(type.value.array.typeId)), type.value.array.size } }; + { mod_to_thing_type(mod, *mod->type_at(type.value.array.typeId)), type.value.array.size } }; } default: throw std::runtime_error("invalid thing type"); } } -thing_type* executor::thing_type(const mod_h& mod, const mod_type& type) const { +thing_type* executor::mod_to_thing_type(const mod_h& mod, const mod_type& type) const { struct thing_type thingType = thing_type_impl(mod, type); - return m_context->thing_type_store().insert(thingType); + return m_context->tt_store().insert(thingType); } void executor::push_frame(const mod_h& mod, function function) { @@ -56,13 +56,13 @@ void executor::push_frame(const mod_h& mod, function function) { args.reserve(signature.params.size()); for (const auto& param : signature.params) { auto arg = pop_thing(); - if (arg->type() != *thing_type(mod, *param)) throw std::runtime_error("function argument type mismatch"); + if (arg->type() != *mod_to_thing_type(mod, *param)) throw std::runtime_error("function argument type mismatch"); args.push_back(std::move(arg)); } struct thing_type* returnType = nullptr; if (function.signature().returnType.has_value()) - returnType = thing_type(mod, *function.signature().returnType.value()); // NOLINT + returnType = mod_to_thing_type(mod, *function.signature().returnType.value()); // NOLINT switch (function.type()) { case function_t::Normal: { @@ -131,45 +131,45 @@ void executor::step() { struct frame& frame = m_frames.top(); - instruction_t instr = static_cast((*frame.mod).byte(frame.position++)); + instruction_t instr = static_cast((*frame.mod).byte_at(frame.position++)); switch (instr) { case instruction_t::NoOperation: break; case instruction_t::PushS8: { push_thing({ (struct thing_type){ thing_type::S8 }, m_context->thing_alloc() })->get() = - static_cast(frame.mod->byte(frame.position++)); + static_cast(frame.mod->byte_at(frame.position++)); } break; case instruction_t::PushU8: { push_thing({ (struct thing_type){ thing_type::U8 }, m_context->thing_alloc() })->get() = - static_cast(frame.mod->byte(frame.position++)); + static_cast(frame.mod->byte_at(frame.position++)); } break; case instruction_t::PushS16: { - thing_type::u16 value = frame.mod->byte(frame.position++); - value |= static_cast(frame.mod->byte(frame.position++) << 8); + thing_type::u16 value = frame.mod->byte_at(frame.position++); + value |= static_cast(frame.mod->byte_at(frame.position++) << 8); push_thing({ (struct thing_type){ thing_type::S16 }, m_context->thing_alloc() })->get() = static_cast(value); } break; case instruction_t::PushU16: { - thing_type::u16 value = frame.mod->byte(frame.position++); - value |= static_cast(frame.mod->byte(frame.position++) << 8); + thing_type::u16 value = frame.mod->byte_at(frame.position++); + value |= static_cast(frame.mod->byte_at(frame.position++) << 8); push_thing({ (struct thing_type){ thing_type::U16 }, m_context->thing_alloc() })->get() = value; } break; case instruction_t::PushS32: { push_thing({ (struct thing_type){ thing_type::S32 }, m_context->thing_alloc() })->get() = - static_cast(frame.mod->byte(frame.position++)); + static_cast(frame.mod->byte_at(frame.position++)); } break; case instruction_t::PushU32: { push_thing({ (struct thing_type){ thing_type::U32 }, m_context->thing_alloc() })->get() = - static_cast(frame.mod->byte(frame.position++)); + static_cast(frame.mod->byte_at(frame.position++)); } break; case instruction_t::Array: { - mod_type_id typeId = static_cast(frame.mod->byte(frame.position)) | - (static_cast(frame.mod->byte(frame.position + 1)) << 8) | - (static_cast(frame.mod->byte(frame.position + 2)) << 16) | - (static_cast(frame.mod->byte(frame.position + 3)) << 24); + mod_type_id typeId = static_cast(frame.mod->byte_at(frame.position)) | + (static_cast(frame.mod->byte_at(frame.position + 1)) << 8) | + (static_cast(frame.mod->byte_at(frame.position + 2)) << 16) | + (static_cast(frame.mod->byte_at(frame.position + 3)) << 24); frame.position += 4; - const auto& type = *thing_type(frame.mod, *frame.mod->type_at(typeId)); + const auto& type = *mod_to_thing_type(frame.mod, *frame.mod->type_at(typeId)); if (type.type != thing_type::Array || type.value.array.type == nullptr || type.value.array.type == &type) throw std::runtime_error("invalid array type"); @@ -209,7 +209,7 @@ void executor::step() { } break; case instruction_t::Reference: { auto thing = pop_thing(); - push_thing({ (struct thing_type){ thing_type::Ref, m_context->thing_type_store().insert(thing->type()) }, + push_thing({ (struct thing_type){ thing_type::Ref, m_context->tt_store().insert(thing->type()) }, m_context->thing_alloc() }) ->reference(*thing); } break; @@ -270,9 +270,8 @@ void executor::step() { } break; case instruction_t::Pointerof: { auto thing = pop_thing(); - auto ptr = - push_thing({ (struct thing_type){ thing_type::Ptr, m_context->thing_type_store().at(thing->type().id) }, - m_context->thing_alloc() }); + auto ptr = push_thing({ (struct thing_type){ thing_type::Ptr, m_context->tt_store().at(thing->type().id) }, + m_context->thing_alloc() }); ptr->get() = thing->raw(); } break; case instruction_t::Sizeof: { @@ -305,29 +304,29 @@ void executor::step() { length->get() = thing->length(); } break; case instruction_t::Load: { - variable_t variable = static_cast(frame.mod->byte(frame.position)) | - (static_cast(frame.mod->byte(frame.position + 1)) << 8); + variable_t variable = static_cast(frame.mod->byte_at(frame.position)) | + (static_cast(frame.mod->byte_at(frame.position + 1)) << 8); frame.position += 2; push_thing(load_thing(variable)); } break; case instruction_t::Store: { - variable_t variable = static_cast(frame.mod->byte(frame.position)) | - (static_cast(frame.mod->byte(frame.position + 1)) << 8); + variable_t variable = static_cast(frame.mod->byte_at(frame.position)) | + (static_cast(frame.mod->byte_at(frame.position + 1)) << 8); frame.position += 2; store_thing(variable, std::move(pop_thing())); } break; case instruction_t::Call: { - function_id funcId = static_cast(frame.mod->byte(frame.position)) | - (static_cast(frame.mod->byte(frame.position + 1)) << 8); + function_id funcId = static_cast(frame.mod->byte_at(frame.position)) | + (static_cast(frame.mod->byte_at(frame.position + 1)) << 8); frame.position += 2; push_frame(frame.mod, *frame.mod->function_at(funcId)); } break; case instruction_t::Jump: { - std::int8_t offset = static_cast(frame.mod->byte(frame.position++)); + std::int8_t offset = static_cast(frame.mod->byte_at(frame.position++)); frame.position += offset; } break; case instruction_t::JumpNotZero: { - byte offset = frame.mod->byte(frame.position++); + byte offset = frame.mod->byte_at(frame.position++); auto cond = pop_thing(); if (cond->integer() != 0) frame.position += (std::int8_t)offset; } break;