From 642d57622ac5820d3fde4d89561d0728e24485a1 Mon Sep 17 00:00:00 2001 From: CHatingPython Date: Sun, 5 Jul 2026 14:54:16 +0200 Subject: [PATCH] feat: introduce pointerof operation Introduce pointerof operation and do some side-quests along the way. Refs: #34 Closes: #17 --- furc/include/furc/ast/expression.hpp | 1 + furc/include/furc/front/token.hpp | 23 +-- furc/src/ast.cpp | 2 + furc/src/back/furvm.cpp | 59 +++++-- furc/src/front/ir_generator.cpp | 44 +++-- furc/src/front/lexer.cpp | 1 + furc/src/front/parser.cpp | 36 ++-- furc/src/front/post_process.cpp | 48 +++--- furc/src/main.cpp | 2 +- furlang/include/furlang/ir/instruction.hpp | 184 ++++++++++++++------- furvm/include/furvm/instruction.hpp | 5 + furvm/include/furvm/thing.hpp | 13 +- furvm/src/executor.cpp | 13 ++ 13 files changed, 290 insertions(+), 141 deletions(-) diff --git a/furc/include/furc/ast/expression.hpp b/furc/include/furc/ast/expression.hpp index 2eef710..d03a954 100644 --- a/furc/include/furc/ast/expression.hpp +++ b/furc/include/furc/ast/expression.hpp @@ -113,6 +113,7 @@ enum class unaryop_expression_node_t { PostfixIncrement, /**< Postfix increment */ PrefixDecrement, /**< Prefix decrement */ PostfixDecrement, /**< Postfix decrement */ + Pointerof, /**< Pointerof */ }; /** diff --git a/furc/include/furc/front/token.hpp b/furc/include/furc/front/token.hpp index d457d74..a0bb50d 100644 --- a/furc/include/furc/front/token.hpp +++ b/furc/include/furc/front/token.hpp @@ -147,16 +147,17 @@ static inline std::string operator+(const std::string& str, token_t type) { * @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` */ + None, /**< None */ + Func, /**< `func` */ + Return, /**< `return` */ + If, /**< `if` */ + Else, /**< `else` */ + While, /**< `while` */ + Import, /**< `import` */ + Native, /**< `native` */ + Public, /**< `public` */ + Private, /**< `private` */ + Pointerof, /**< `pointerof` */ Int32, /**< `int32` */ }; @@ -173,6 +174,7 @@ static inline std::ostream& operator<<(std::ostream& os, keyword_token keyword) 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::Int32: return os << "int32"; } return os; @@ -190,6 +192,7 @@ static inline std::string operator+(const std::string& str, keyword_token keywor 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::Int32: return str + "int32"; } return str; diff --git a/furc/src/ast.cpp b/furc/src/ast.cpp index 2b6932b..9fa177e 100644 --- a/furc/src/ast.cpp +++ b/furc/src/ast.cpp @@ -37,6 +37,7 @@ std::ostream& operator<<(std::ostream& os, unaryop_expression_node_t type) { 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"; } return os; } @@ -54,6 +55,7 @@ std::ostream& unary_op_expression_node::print(std::ostream& os) const { 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; } return os; } diff --git a/furc/src/back/furvm.cpp b/furc/src/back/furvm.cpp index cd26e13..7399429 100644 --- a/furc/src/back/furvm.cpp +++ b/furc/src/back/furvm.cpp @@ -2,7 +2,6 @@ #include "furlang/ir/function.hpp" #include "furlang/ir/instruction.hpp" -#include "furvm/function.hpp" #include "furvm/fwd.hpp" #include @@ -56,21 +55,26 @@ void furvm_generator::generate_function(furvm::mod& mod, const furlang::ir::func } } -static inline furvm::instruction_t binary_op_type(furlang::ir::binary_op_instruction_t type) { +static inline furvm::instruction_t op_type(furlang::ir::instruction_t type) { switch (type) { - case furlang::ir::binary_op_instruction_t::Add: return furvm::instruction_t::Add; - case furlang::ir::binary_op_instruction_t::Sub: return furvm::instruction_t::Sub; - case furlang::ir::binary_op_instruction_t::Mul: return furvm::instruction_t::Mul; - case furlang::ir::binary_op_instruction_t::Div: return furvm::instruction_t::Div; - case furlang::ir::binary_op_instruction_t::Mod: return furvm::instruction_t::Mod; - case furlang::ir::binary_op_instruction_t::Eq: return furvm::instruction_t::Equals; - case furlang::ir::binary_op_instruction_t::NotEq: return furvm::instruction_t::NotEquals; - case furlang::ir::binary_op_instruction_t::LessThan: return furvm::instruction_t::LessThan; - case furlang::ir::binary_op_instruction_t::GreaterThan: return furvm::instruction_t::GreaterThan; - case furlang::ir::binary_op_instruction_t::LessEq: return furvm::instruction_t::LessEqual; - case furlang::ir::binary_op_instruction_t::GreaterEq: return furvm::instruction_t::GreaterEqual; + // Unary + case furlang::ir::instruction_t::Pointerof: return furvm::instruction_t::Pointerof; + + // 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"); } - throw std::runtime_error("unreachable"); } void furvm_generator::generate_instruction(furvm::mod& mod, @@ -90,9 +94,30 @@ void furvm_generator::generate_instruction(furvm::mod& mod, mod.bytecode().push_back((var >> 8) & 0xFF); static_assert(sizeof(var) == 2, "sizeof(furvm::variable_t) has changed"); } break; - case furlang::ir::instruction_t::BinaryOp: { - const auto& op = dynamic_cast(instr); - mod.bytecode().push_back(static_cast(binary_op_type(op.op_type()))); + 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: { + 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++; diff --git a/furc/src/front/ir_generator.cpp b/furc/src/front/ir_generator.cpp index 9c40260..5bb057e 100644 --- a/furc/src/front/ir_generator.cpp +++ b/furc/src/front/ir_generator.cpp @@ -132,23 +132,35 @@ void ir_generator::visit(const ast::var_read_expression_node& node) { } } -void ir_generator::visit(const ast::unary_op_expression_node& node) { - throw std::runtime_error("unimplemented"); +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; + default: throw std::runtime_error("unimplemented"); + } } -static inline furlang::ir::binary_op_instruction_t binary_op_instruction_t(ast::binop_expression_node_t type) { +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::binary_op_instruction_t::Add; - case ast::binop_expression_node_t::Sub: return furlang::ir::binary_op_instruction_t::Sub; - case ast::binop_expression_node_t::Mul: return furlang::ir::binary_op_instruction_t::Mul; - case ast::binop_expression_node_t::Div: return furlang::ir::binary_op_instruction_t::Div; - case ast::binop_expression_node_t::Mod: return furlang::ir::binary_op_instruction_t::Mod; - case ast::binop_expression_node_t::Equal: return furlang::ir::binary_op_instruction_t::Eq; - case ast::binop_expression_node_t::NotEqual: return furlang::ir::binary_op_instruction_t::NotEq; - case ast::binop_expression_node_t::LessThan: return furlang::ir::binary_op_instruction_t::LessThan; - case ast::binop_expression_node_t::GreaterThan: return furlang::ir::binary_op_instruction_t::GreaterThan; - case ast::binop_expression_node_t::LessEqual: return furlang::ir::binary_op_instruction_t::LessEq; - case ast::binop_expression_node_t::GreaterEqual: return furlang::ir::binary_op_instruction_t::GreaterEq; + 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"); } @@ -160,7 +172,7 @@ void ir_generator::visit(const ast::binary_op_expression_node& node) { node.rhs()->accept(*this); ir_register rhs = m_registerCounter - 1; ir_register dst = m_registerCounter++; - push(binary_op_instruction_t(node.type()), + push(binary_op_instruction_t(node.type()), ir::operand::new_reg(lhs), ir::operand::new_reg(rhs), ir::operand::new_reg(dst)); @@ -176,7 +188,7 @@ void ir_generator::visit(const ast::var_assign_expression_node& node) { auto compound = node.compound(); if (compound != ast::binop_expression_node_t::None) { - push(binary_op_instruction_t(compound), + push(binary_op_instruction_t(compound), ir::operand::new_reg(reg), ir::operand::new_reg(rhs), ir::operand::new_reg(reg)); diff --git a/furc/src/front/lexer.cpp b/furc/src/front/lexer.cpp index 8709d7a..37903c1 100644 --- a/furc/src/front/lexer.cpp +++ b/furc/src/front/lexer.cpp @@ -104,6 +104,7 @@ token_r lexer::next_token() { { "native", keyword_token::Native }, { "public", keyword_token::Public }, { "private", keyword_token::Private }, + { "pointerof", keyword_token::Pointerof }, { "int32", keyword_token::Int32 }, }; diff --git a/furc/src/front/parser.cpp b/furc/src/front/parser.cpp index ee98695..3cd0630 100644 --- a/furc/src/front/parser.cpp +++ b/furc/src/front/parser.cpp @@ -9,6 +9,7 @@ #include "furc/front/token.hpp" #include +#include #include #include #include @@ -313,27 +314,42 @@ struct unaryop_info { std::uint32_t precedence; }; -ast::expression_node_r parser::parse_expression_unary(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, 3 } }, - { token_t::Minus, unaryop_info{ ast::unaryop_expression_node_t::Negative, 3 } }, + { 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 } }, + }; + 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 it = s_prefixes.find(peek_token()->type); - if (it == s_prefixes.end()) break; - auto current = it->second; + 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; - auto nextIt = s_prefixes.find(peek_token()->type); - if (nextIt != s_prefixes.end()) { - auto next = nextIt->second; + 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 }); @@ -464,7 +480,7 @@ ast::expression_node_r parser::parse_expression_rhs(ast::expression_node_p&& ini } 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(current.precedence + 1); + auto expr = parse_expression_unary(16); if (expr.has_error()) { return ast::expression_node_r(ast::error{ expr.error().location }); } diff --git a/furc/src/front/post_process.cpp b/furc/src/front/post_process.cpp index 2717e78..e43e735 100644 --- a/furc/src/front/post_process.cpp +++ b/furc/src/front/post_process.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -427,7 +428,17 @@ static void sccp_stage(function_context& ctx) { case furlang::ir::instruction_t::Assign: { newLat = sccp_stage_get_lattice(latticeValues, *instr->sources().front()); } break; - case furlang::ir::instruction_t::BinaryOp: { + 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]); @@ -435,40 +446,31 @@ static void sccp_stage(function_context& ctx) { newLat.type = lattice::Bottom; } else if (lhs.type == lattice::Constant && rhs.type == lattice::Constant) { newLat.type = lattice::Constant; - switch (dynamic_cast(*instr).op_type()) { - case furlang::ir::binary_op_instruction_t::Add: - newLat.constant = lhs.constant + rhs.constant; - break; - case furlang::ir::binary_op_instruction_t::Sub: - newLat.constant = lhs.constant - rhs.constant; - break; - case furlang::ir::binary_op_instruction_t::Mul: - newLat.constant = lhs.constant * rhs.constant; - break; - case furlang::ir::binary_op_instruction_t::Div: - newLat.constant = lhs.constant / rhs.constant; - break; - case furlang::ir::binary_op_instruction_t::Mod: - newLat.constant = lhs.constant % rhs.constant; - break; - case furlang::ir::binary_op_instruction_t::Eq: + 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::binary_op_instruction_t::NotEq: + case furlang::ir::instruction_t::NotEq: newLat.constant = (lhs.constant != rhs.constant) ? 1 : 0; break; - case furlang::ir::binary_op_instruction_t::LessThan: + case furlang::ir::instruction_t::LessThan: newLat.constant = (lhs.constant < rhs.constant) ? 1 : 0; break; - case furlang::ir::binary_op_instruction_t::GreaterThan: + case furlang::ir::instruction_t::GreaterThan: newLat.constant = (lhs.constant > rhs.constant) ? 1 : 0; break; - case furlang::ir::binary_op_instruction_t::LessEq: + case furlang::ir::instruction_t::LessEq: newLat.constant = (lhs.constant <= rhs.constant) ? 1 : 0; break; - case furlang::ir::binary_op_instruction_t::GreaterEq: + case furlang::ir::instruction_t::GreaterEq: newLat.constant = (lhs.constant >= rhs.constant) ? 1 : 0; break; + default: throw std::runtime_error("unreachable"); } } } break; diff --git a/furc/src/main.cpp b/furc/src/main.cpp index 45d8de4..c718354 100644 --- a/furc/src/main.cpp +++ b/furc/src/main.cpp @@ -23,7 +23,7 @@ int main(void) { while (x < y) { x = x + z; } - print(x); + print(pointerof x); } )"; furlang::arena arena{}; diff --git a/furlang/include/furlang/ir/instruction.hpp b/furlang/include/furlang/ir/instruction.hpp index bf626a6..e47651d 100644 --- a/furlang/include/furlang/ir/instruction.hpp +++ b/furlang/include/furlang/ir/instruction.hpp @@ -18,16 +18,51 @@ namespace ir { * @brief IR instruction type. */ enum class instruction_t { - Alloca, /**< Unused */ - Assign, /**< Assign */ - BinaryOp, /**< Binary operation */ - Call, /**< Call */ - Branch, /**< Branch */ - BranchCond, /**< Conditional branch */ - Return, /**< Return */ - Phi, /**< Phi function */ + Alloca, /**< Unused */ + Assign, /**< Assign */ + Add, /**< Addition */ + Sub, /**< Subtraction */ + Mul, /**< Multiplication */ + Div, /**< Division */ + Mod, /**< Modulo */ + Eq, /**< Equal */ + NotEq, /**< Not equal */ + LessThan, /**< Less than */ + GreaterThan, /**< Greater than */ + LessEq, /**< Less or equal */ + GreaterEq, /**< Greater or equal */ + Pointerof, /**< Pointerof */ + Call, /**< Call */ + Branch, /**< Branch */ + BranchCond, /**< Conditional branch */ + Return, /**< Return */ + Phi, /**< Phi function */ }; +static inline std::ostream& operator<<(std::ostream& os, instruction_t type) { + switch (type) { + case instruction_t::Alloca: return os << "alloca"; + case instruction_t::Assign: return os << "assign"; + case instruction_t::Add: return os << "add"; + case instruction_t::Sub: return os << "sub"; + case instruction_t::Mul: return os << "mul"; + case instruction_t::Div: return os << "div"; + case instruction_t::Mod: return os << "mod"; + case instruction_t::Eq: return os << "eq"; + case instruction_t::NotEq: return os << "notEq"; + case instruction_t::LessThan: return os << "lessThan"; + case instruction_t::GreaterThan: return os << "greaterThan"; + case instruction_t::LessEq: return os << "lessEq"; + case instruction_t::GreaterEq: return os << "greaterEq"; + case instruction_t::Pointerof: return os << "pointerof"; + case instruction_t::Call: return os << "call"; + case instruction_t::Branch: return os << "branch"; + case instruction_t::BranchCond: return os << "branchCond"; + case instruction_t::Return: return os << "return"; + case instruction_t::Phi: return os << "phi"; + } +} + /** * @brief Checks if an instruction type exits. * @@ -241,78 +276,112 @@ protected: }; /** - * @brief Binary operation instruction type + * @brief Generic unary instruction */ -enum class binary_op_instruction_t { - Add, /**< Addition */ - Sub, /**< Subtraction */ - Mul, /**< Multiplication */ - Div, /**< Division */ - Mod, /**< Modulo */ +class unary_instruction final : public instruction { +public: + /** + * @brief Construct a new unary instruction. + * + * @param type Instruction type. + * @param src Source operand. + * @param dst Destination operand. + */ + unary_instruction(instruction_t type, operand&& src, operand&& dst) + : m_type(type), m_src(std::move(src)), m_dst(std::move(dst)) {} - Eq, /**< Equal */ - NotEq, /**< Not equal */ - LessThan, /**< Less than */ - GreaterThan, /**< Greater than */ - LessEq, /**< Less or equal */ - GreaterEq, /**< Greater or equal */ + ~unary_instruction() override = default; + + /** + * @brief Move constructor + */ + unary_instruction(unary_instruction&&) = default; + + /** + * @brief Move constructor + */ + unary_instruction& operator=(unary_instruction&&) = default; + + unary_instruction(const unary_instruction&) = delete; + + unary_instruction& operator=(const unary_instruction&) = delete; +public: + /** + * @brief Returns this instruction's type. + * + * @return The instruction type. + */ + instruction_t type() const override { return m_type; } + + bool has_destination() const override { return true; } + + operand& destination() override { return m_dst; } + + const operand& destination() const override { return m_dst; } + + std::vector sources() override { return { &m_src }; } + + std::vector sources() const override { return { &m_src }; } + + /** + * @brief Returns this instruction's source operand. + * + * @return The operand. + */ + const operand& src() const { return m_src; } + + /** + * @brief Returns this instruction's destination operand. + * + * @return The operand. + */ + const operand& dst() const { return m_dst; } +private: + instruction_t m_type; + operand m_src; + operand m_dst; +protected: + std::ostream& print(std::ostream& os) const override { return os << m_dst << " = " << m_type << ' ' << m_src; } }; -static inline std::ostream& operator<<(std::ostream& os, binary_op_instruction_t type) { - switch (type) { - case binary_op_instruction_t::Add: return os << '+'; - case binary_op_instruction_t::Sub: return os << '-'; - case binary_op_instruction_t::Mul: return os << '*'; - case binary_op_instruction_t::Div: return os << '/'; - case binary_op_instruction_t::Mod: return os << '%'; - case binary_op_instruction_t::Eq: return os << "=="; - case binary_op_instruction_t::NotEq: return os << "!="; - case binary_op_instruction_t::LessThan: return os << '<'; - case binary_op_instruction_t::GreaterThan: return os << '>'; - case binary_op_instruction_t::LessEq: return os << "<="; - case binary_op_instruction_t::GreaterEq: return os << ">="; - } - return os; -} - /** - * @brief Binary operation instruction + * @brief Generic binary instruction */ -class binary_op_instruction final : public instruction { +class binary_instruction final : public instruction { public: /** * @brief Construct a new binary operation instruction. * - * @param type Operation type. + * @param type Instruction type. * @param lhs Left-hand-side operand. * @param rhs Right-hand-side operand. * @param dst Destination operand. */ - binary_op_instruction(binary_op_instruction_t type, operand&& lhs, operand&& rhs, operand&& dst) + binary_instruction(instruction_t type, operand&& lhs, operand&& rhs, operand&& dst) : m_type(type), m_lhs(std::move(lhs)), m_rhs(std::move(rhs)), m_dst(std::move(dst)) {} - ~binary_op_instruction() override = default; + ~binary_instruction() override = default; /** * @brief Move constructor */ - binary_op_instruction(binary_op_instruction&&) = default; + binary_instruction(binary_instruction&&) = default; /** * @brief Move constructor */ - binary_op_instruction& operator=(binary_op_instruction&&) = default; + binary_instruction& operator=(binary_instruction&&) = default; - binary_op_instruction(const binary_op_instruction&) = delete; + binary_instruction(const binary_instruction&) = delete; - binary_op_instruction& operator=(const binary_op_instruction&) = delete; + binary_instruction& operator=(const binary_instruction&) = delete; public: /** * @brief Returns this instruction's type. * * @return instruction_t::BinaryOp. */ - instruction_t type() const override { return instruction_t::BinaryOp; } + instruction_t type() const override { return m_type; } bool has_destination() const override { return true; } @@ -324,13 +393,6 @@ public: std::vector sources() const override { return { &m_lhs, &m_rhs }; } - /** - * @brief Returns this instruction's operation type. - * - * @return The operation type. - */ - binary_op_instruction_t op_type() const { return m_type; } - /** * @brief Returns this instruction's left-hand-side operand. * @@ -352,13 +414,13 @@ public: */ const operand& dst() const { return m_dst; } private: - binary_op_instruction_t m_type; - operand m_lhs /**< Left-hand-side operand */; - operand m_rhs /**< Right-hand-side operand */; - operand m_dst /**< Destination operand */; + instruction_t m_type; + operand m_lhs /**< Left-hand-side operand */; + operand m_rhs /**< Right-hand-side operand */; + operand m_dst /**< Destination operand */; protected: std::ostream& print(std::ostream& os) const override { - return os << "binop(" << m_type << ") " << m_lhs << ", " << m_rhs << ", " << m_dst; + return os << m_dst << " = " << m_lhs << ' ' << m_type << ' ' << m_rhs; } }; @@ -617,7 +679,7 @@ private: std::vector> m_labels; protected: std::ostream& print(std::ostream& os) const override { - os << "phi " << m_dst << " ="; + os << m_dst << " = phi"; bool first = true; for (const auto& pair : m_labels) { if (!first) os << ','; diff --git a/furvm/include/furvm/instruction.hpp b/furvm/include/furvm/instruction.hpp index b728a9a..2304560 100644 --- a/furvm/include/furvm/instruction.hpp +++ b/furvm/include/furvm/instruction.hpp @@ -102,6 +102,11 @@ enum class instruction_t : byte { */ GreaterEqual, + /** + * @brief Pushes a pointer of popped-off thing onto the stack. + */ + Pointerof, + /** * @brief Pushes a variable onto the stack. * diff --git a/furvm/include/furvm/thing.hpp b/furvm/include/furvm/thing.hpp index 7ead4b5..3a56d5d 100644 --- a/furvm/include/furvm/thing.hpp +++ b/furvm/include/furvm/thing.hpp @@ -114,6 +114,13 @@ public: * @return The type. */ constexpr auto type() const { return *m_type; } + + /** + * @brief Returns the thing's type. + * + * @return The shared pointer to the type. + */ + auto type() { return m_type; } public: /** * @brief Returns a raw data pointer. @@ -265,7 +272,7 @@ public: thing resolve() const { thing rsv = { resolve_type(m_type, m_modules), m_data, m_allocator }; - while (rsv.type().t == type_t::Reference) + while (rsv.type()->t == type_t::Reference) rsv = { rsv.m_type->reference, rsv.get(), std::move(rsv.m_allocator) }; return rsv; } @@ -342,8 +349,8 @@ private: private: template thing binary_op(const thing& rhs, const Op& op) const { - thing lhsRsv = resolve(); - thing rhsRsv = rhs.resolve(); + const thing lhsRsv = resolve(); + const thing rhsRsv = rhs.resolve(); if (lhsRsv.type().t == type_t::Primitive && rhsRsv.type().t == type_t::Primitive) { std::size_t size = std::max(lhsRsv.type().primitive, rhsRsv.type().primitive); diff --git a/furvm/src/executor.cpp b/furvm/src/executor.cpp index 68cca56..bcbe516 100644 --- a/furvm/src/executor.cpp +++ b/furvm/src/executor.cpp @@ -162,6 +162,19 @@ void executor::step() { auto lhs = pop_thing(); push_thing(lhs->greater_equals(*rhs)); } break; + case instruction_t::Pointerof: { + auto thing = pop_thing()->resolve(); + auto ptr = push_thing({ *m_context->at("core")->type_at(4), m_context, m_context->thing_alloc() }); + switch (furvm::thing<>::resolve_type(thing.type(), m_context)->t) { + case type_t::Primitive: ptr->get() = reinterpret_cast(thing.raw()); break; + case type_t::List: + ptr->get() = reinterpret_cast(thing.get().data); + break; + case type_t::Reference: + case type_t::Import: + default: throw std::runtime_error("unreachable"); + } + } break; case instruction_t::Load: { variable_t variable = static_cast(frame.mod->byte(frame.position)) | (static_cast(frame.mod->byte(frame.position + 1)) << 8);